bruce-cesium 7.4.1 → 7.4.3
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/bruce-cesium.es5.js +295 -159
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +293 -157
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-gatherer.js +50 -51
- package/dist/lib/rendering/entity-gatherer.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine.js +56 -26
- package/dist/lib/rendering/entity-render-engine.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label.js +185 -78
- package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/entity-gatherer.d.ts +2 -1
- package/dist/types/rendering/entity-render-engine.d.ts +1 -0
- package/dist/types/rendering/render-managers/common/entity-label.d.ts +4 -1
- package/package.json +1 -1
|
@@ -33,7 +33,14 @@ var EntityLabel;
|
|
|
33
33
|
(function (EntityLabel) {
|
|
34
34
|
const ICON_BACKGROUND_BLEND = 0.8;
|
|
35
35
|
const ICON_BACKGROUND_ALPHA = 0.45;
|
|
36
|
+
// Under this much difference between the glyph's width and height the chip is squared off,
|
|
37
|
+
// so a row of labels reads as one size rather than a set of differently shaped pills.
|
|
38
|
+
const ICON_BACKGROUND_UNIFORM_TOLERANCE = 0.3;
|
|
36
39
|
const TEXT_MAX_WIDTH = 200;
|
|
40
|
+
// How far an angled leader runs sideways before the label starts.
|
|
41
|
+
const ANGLED_LEADER_RUN = 28;
|
|
42
|
+
// One per tinted icon, since an SVG mask is addressed by id across the whole document.
|
|
43
|
+
let tintCounter = 0;
|
|
37
44
|
// Key where the label instance is stored within the cesium entity.
|
|
38
45
|
// Eg: rego[ATTACH_KEY] = new EntityLabel(...);
|
|
39
46
|
EntityLabel.ATTACH_KEY = "nextspace-navigator-entity-label";
|
|
@@ -132,7 +139,7 @@ var EntityLabel;
|
|
|
132
139
|
this.nextOrder = 0;
|
|
133
140
|
}
|
|
134
141
|
Resolve(frames) {
|
|
135
|
-
var _a, _b;
|
|
142
|
+
var _a, _b, _c;
|
|
136
143
|
const live = new Set(frames.map(frame => frame.id));
|
|
137
144
|
const moved = (frame) => {
|
|
138
145
|
var _a;
|
|
@@ -159,10 +166,17 @@ var EntityLabel;
|
|
|
159
166
|
const placed = new Map();
|
|
160
167
|
const next = new Map();
|
|
161
168
|
const candidate = (frame, side) => {
|
|
162
|
-
var _a;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
var _a, _b;
|
|
170
|
+
if (!frame.canFlip) {
|
|
171
|
+
return frame;
|
|
172
|
+
}
|
|
173
|
+
if (frame.leaderRun != null) {
|
|
174
|
+
const x = side === "left" ? frame.anchorX - frame.leaderRun - frame.width : frame.anchorX + frame.leaderRun;
|
|
175
|
+
return { ...frame, x: Math.max(0, Math.min(x, ((_a = frame.viewportWidth) !== null && _a !== void 0 ? _a : Infinity) - frame.width)) };
|
|
176
|
+
}
|
|
177
|
+
return (side === "left" ?
|
|
178
|
+
{ ...frame, x: Math.max(0, Math.min(frame.anchorX - frame.width, ((_b = frame.viewportWidth) !== null && _b !== void 0 ? _b : Infinity) - frame.width)) }
|
|
179
|
+
: frame);
|
|
166
180
|
};
|
|
167
181
|
const score = (frame, padding = 0) => {
|
|
168
182
|
const box = {
|
|
@@ -178,7 +192,7 @@ var EntityLabel;
|
|
|
178
192
|
};
|
|
179
193
|
for (const frame of ordered) {
|
|
180
194
|
const old = this.previous.get(frame.id);
|
|
181
|
-
let side = frame.canFlip ? (_a = old === null || old === void 0 ? void 0 : old.side) !== null && _a !== void 0 ? _a : "right" : "right";
|
|
195
|
+
let side = frame.canFlip ? (_b = (_a = old === null || old === void 0 ? void 0 : old.side) !== null && _a !== void 0 ? _a : frame.leaderSide) !== null && _b !== void 0 ? _b : "right" : "right";
|
|
182
196
|
let chosen = candidate(frame, side);
|
|
183
197
|
if (!fixed(frame) && frame.canFlip) {
|
|
184
198
|
const otherSide = side === "left" ? "right" : "left";
|
|
@@ -190,7 +204,7 @@ var EntityLabel;
|
|
|
190
204
|
}
|
|
191
205
|
}
|
|
192
206
|
placed.set(frame.id, { frame: chosen, side });
|
|
193
|
-
next.set(frame.id, { frame: fixed(frame) ? old.frame : { ...frame }, side, order: (
|
|
207
|
+
next.set(frame.id, { frame: fixed(frame) ? old.frame : { ...frame }, side, order: (_c = old === null || old === void 0 ? void 0 : old.order) !== null && _c !== void 0 ? _c : this.nextOrder++ });
|
|
194
208
|
text.Add(chosen);
|
|
195
209
|
const stem = leaderBounds(chosen);
|
|
196
210
|
if (stem) {
|
|
@@ -210,7 +224,7 @@ var EntityLabel;
|
|
|
210
224
|
* Resolves clustering and stable text placement before depth fading; highlighted labels receive priority.
|
|
211
225
|
*/
|
|
212
226
|
function Layout(input, memory = new PlacementMemory()) {
|
|
213
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
227
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
214
228
|
const frames = input.filter(frame => [frame.x, frame.y, frame.width, frame.height, frame.depth].every(Number.isFinite))
|
|
215
229
|
.sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.depth - b.depth || a.id.localeCompare(b.id));
|
|
216
230
|
const result = new Map();
|
|
@@ -276,17 +290,13 @@ var EntityLabel;
|
|
|
276
290
|
}
|
|
277
291
|
}
|
|
278
292
|
if (values.size > 1) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (values.size > 2)
|
|
287
|
-
rows.push(`+${values.size - 2} more…`);
|
|
288
|
-
representative.text = rows.join("\n");
|
|
289
|
-
}
|
|
293
|
+
// A value long enough to wrap fills the box on its own, so only one is listed.
|
|
294
|
+
const wrapped = stableMembers.some(member => { var _a, _b; return member.textWrapped && ((_b = (member.text || ((_a = member.options) === null || _a === void 0 ? void 0 : _a.text))) === null || _b === void 0 ? void 0 : _b.trim()); });
|
|
295
|
+
const limit = wrapped ? 1 : 2;
|
|
296
|
+
const rows = Array.from(values).slice(0, limit);
|
|
297
|
+
if (values.size > limit)
|
|
298
|
+
rows.push(`+${values.size - limit} more…`);
|
|
299
|
+
representative.text = rows.join("\n");
|
|
290
300
|
}
|
|
291
301
|
}
|
|
292
302
|
for (const frame of cluster.members) {
|
|
@@ -310,7 +320,7 @@ var EntityLabel;
|
|
|
310
320
|
const box = { ...frame, x: frame.x + .01, y: frame.y + .01, width: Math.max(0, frame.width - .02), height: Math.max(0, frame.height - .02) };
|
|
311
321
|
const overlap = foreground.HasOverlap(box) || foregroundLeaders.HasOverlap(box) || Boolean(stem && foreground.HasOverlap(stem));
|
|
312
322
|
if (overlap) {
|
|
313
|
-
placement.opacity *= Math.max(0, Math.min(1, (
|
|
323
|
+
placement.opacity *= Math.max(0, Math.min(1, (_g = (_f = frame.options) === null || _f === void 0 ? void 0 : _f.overlapOpacity) !== null && _g !== void 0 ? _g : 0.25));
|
|
314
324
|
}
|
|
315
325
|
;
|
|
316
326
|
placement.zIndex = zIndex--;
|
|
@@ -633,6 +643,8 @@ var EntityLabel;
|
|
|
633
643
|
this.loadTimeout = null;
|
|
634
644
|
this.loadedName = false;
|
|
635
645
|
this.line = null;
|
|
646
|
+
// The sideways half of an angled leader; the rise is drawn by line.
|
|
647
|
+
this.leaderRun = null;
|
|
636
648
|
this.anchor = null;
|
|
637
649
|
// Null = not attempted to load.
|
|
638
650
|
this.additionalTexts = null;
|
|
@@ -1029,6 +1041,7 @@ var EntityLabel;
|
|
|
1029
1041
|
}
|
|
1030
1042
|
};
|
|
1031
1043
|
const normalLeader = (_k = this.options.leader) !== null && _k !== void 0 ? _k : presentation === "text";
|
|
1044
|
+
const angled = this.options.leaderStyle === "angled";
|
|
1032
1045
|
let leader = normalLeader;
|
|
1033
1046
|
const content = document.createElement("span");
|
|
1034
1047
|
const originalText = (_l = this.options.text) !== null && _l !== void 0 ? _l : [text, ...additionalTexts].join("\n");
|
|
@@ -1037,6 +1050,7 @@ var EntityLabel;
|
|
|
1037
1050
|
let sourceNaturalText;
|
|
1038
1051
|
let iconElement;
|
|
1039
1052
|
let iconContainer;
|
|
1053
|
+
let fitIconBackground;
|
|
1040
1054
|
content.className = "entity-label-content";
|
|
1041
1055
|
content.style.cssText = "display:flex;align-items:center;gap:6px;";
|
|
1042
1056
|
if (presentation === "icon-text-above") {
|
|
@@ -1059,34 +1073,49 @@ var EntityLabel;
|
|
|
1059
1073
|
image.alt = this.options.icon || "";
|
|
1060
1074
|
const scale = (_o = this.options.iconScale) !== null && _o !== void 0 ? _o : 1;
|
|
1061
1075
|
const size = this.options.iconSize;
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
mask
|
|
1069
|
-
mask.
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
1077
|
+
const tint = iconColor ? document.createElementNS(svgNs, "svg") : null;
|
|
1078
|
+
const painted = tint ? document.createElementNS(svgNs, "image") : null;
|
|
1079
|
+
const inked = tint ? document.createElementNS(svgNs, "rect") : null;
|
|
1080
|
+
if (tint) {
|
|
1081
|
+
const maskId = `entity-label-tint-${++tintCounter}`;
|
|
1082
|
+
const mask = document.createElementNS(svgNs, "mask");
|
|
1083
|
+
mask.setAttribute("id", maskId);
|
|
1084
|
+
mask.setAttribute("maskUnits", "userSpaceOnUse");
|
|
1085
|
+
painted.setAttribute("href", this.options.iconUrl);
|
|
1086
|
+
painted.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
1087
|
+
mask.appendChild(painted);
|
|
1088
|
+
inked.setAttribute("fill", iconColor);
|
|
1089
|
+
inked.setAttribute("mask", `url(#${maskId})`);
|
|
1090
|
+
tint.append(mask, inked);
|
|
1091
|
+
tint.style.display = "block";
|
|
1092
|
+
icon.style.display = "inline-flex";
|
|
1093
|
+
icon.appendChild(tint);
|
|
1076
1094
|
}
|
|
1077
1095
|
const resize = () => {
|
|
1078
1096
|
if (this.disposed || this.counter !== counter) {
|
|
1079
1097
|
return;
|
|
1080
1098
|
}
|
|
1081
1099
|
const intrinsic = this.options.iconScale != null && size == null;
|
|
1082
|
-
|
|
1083
|
-
|
|
1100
|
+
const width = (intrinsic ? image.naturalWidth || 24 : size || 24) * scale;
|
|
1101
|
+
const height = (intrinsic ? image.naturalHeight || 24 : size || 24) * scale;
|
|
1102
|
+
if (tint) {
|
|
1103
|
+
tint.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
1104
|
+
for (const node of [tint, painted, inked]) {
|
|
1105
|
+
node.setAttribute("width", String(width));
|
|
1106
|
+
node.setAttribute("height", String(height));
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
else {
|
|
1110
|
+
image.style.width = `${width}px`;
|
|
1111
|
+
image.style.height = `${height}px`;
|
|
1112
|
+
}
|
|
1084
1113
|
this.viewer.scene.requestRender();
|
|
1085
1114
|
};
|
|
1086
1115
|
image.onload = resize;
|
|
1087
1116
|
resize();
|
|
1088
1117
|
image.src = this.options.iconUrl;
|
|
1089
|
-
if (!
|
|
1118
|
+
if (!tint) {
|
|
1090
1119
|
icon.appendChild(image);
|
|
1091
1120
|
}
|
|
1092
1121
|
}
|
|
@@ -1111,6 +1140,27 @@ var EntityLabel;
|
|
|
1111
1140
|
icon.style.minWidth = `${size}px`;
|
|
1112
1141
|
icon.style.minHeight = `${size}px`;
|
|
1113
1142
|
icon.style.boxSizing = "content-box";
|
|
1143
|
+
let fitted = false;
|
|
1144
|
+
fitIconBackground = () => {
|
|
1145
|
+
if (fitted) {
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
const padding = size / 3;
|
|
1149
|
+
const width = icon.offsetWidth - padding * 2;
|
|
1150
|
+
const height = icon.offsetHeight - padding * 2;
|
|
1151
|
+
if (width <= 0 || height <= 0) {
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
fitted = true;
|
|
1155
|
+
const longest = Math.max(width, height);
|
|
1156
|
+
const difference = (longest - Math.min(width, height)) / longest;
|
|
1157
|
+
if (difference > ICON_BACKGROUND_UNIFORM_TOLERANCE) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
icon.style.minWidth = `${longest}px`;
|
|
1161
|
+
icon.style.minHeight = `${longest}px`;
|
|
1162
|
+
this.viewer.scene.requestRender();
|
|
1163
|
+
};
|
|
1114
1164
|
}
|
|
1115
1165
|
if (this.options.iconScale === 0) {
|
|
1116
1166
|
icon.style.display = "none";
|
|
@@ -1149,8 +1199,10 @@ var EntityLabel;
|
|
|
1149
1199
|
const countElement = document.createElement("span");
|
|
1150
1200
|
countElement.className = "entity-label-count";
|
|
1151
1201
|
countElement.style.cssText = "flex:none;align-self:center;white-space:nowrap;background:#fff;color:#000;text-shadow:none;border-radius:8px;padding:0 3px;display:none;";
|
|
1202
|
+
// Text above the icon would have the badge land in it, so the free corner is the lower one.
|
|
1203
|
+
const badgeBelow = presentation === "icon-text-above";
|
|
1152
1204
|
if (iconContainer) {
|
|
1153
|
-
countElement.style.cssText +=
|
|
1205
|
+
countElement.style.cssText += `position:absolute;left:100%;top:${badgeBelow ? "100%" : "0"};transform:translate(-50%,-50%);`;
|
|
1154
1206
|
iconContainer.appendChild(countElement);
|
|
1155
1207
|
}
|
|
1156
1208
|
if (!layers.has(this.viewer)) {
|
|
@@ -1159,6 +1211,7 @@ var EntityLabel;
|
|
|
1159
1211
|
const layer = layers.get(this.viewer);
|
|
1160
1212
|
let ele = null;
|
|
1161
1213
|
let lineEle = null;
|
|
1214
|
+
let runEle = null;
|
|
1162
1215
|
if (this.label) {
|
|
1163
1216
|
ele = this.label;
|
|
1164
1217
|
}
|
|
@@ -1195,6 +1248,7 @@ var EntityLabel;
|
|
|
1195
1248
|
}
|
|
1196
1249
|
if (this.line) {
|
|
1197
1250
|
lineEle = this.line;
|
|
1251
|
+
runEle = this.leaderRun;
|
|
1198
1252
|
}
|
|
1199
1253
|
else {
|
|
1200
1254
|
lineEle = document.createElement("div");
|
|
@@ -1238,6 +1292,14 @@ var EntityLabel;
|
|
|
1238
1292
|
layer.element.appendChild(lineEleNode);
|
|
1239
1293
|
layer.element.appendChild(lineEle);
|
|
1240
1294
|
}
|
|
1295
|
+
// Built here rather than beside the stem, since the style can change on a label that is reused.
|
|
1296
|
+
if (angled && !runEle) {
|
|
1297
|
+
runEle = lineEle.cloneNode(false);
|
|
1298
|
+
runEle.className = "entity-label-leader-run";
|
|
1299
|
+
runEle.style.display = "none";
|
|
1300
|
+
this.leaderRun = runEle;
|
|
1301
|
+
layer.element.appendChild(runEle);
|
|
1302
|
+
}
|
|
1241
1303
|
let MAX_DISTANCE = Math.max(15000, sizeInM * 35);
|
|
1242
1304
|
if (visual && visual instanceof Cesium.Entity) {
|
|
1243
1305
|
// Consistent sized things.
|
|
@@ -1257,6 +1319,25 @@ var EntityLabel;
|
|
|
1257
1319
|
y: upwards ? endY - height : endY, endY
|
|
1258
1320
|
};
|
|
1259
1321
|
};
|
|
1322
|
+
/*
|
|
1323
|
+
* An angled leader parks the label beside the anchor instead of over it,
|
|
1324
|
+
* so the stem rises to the label's middle and then runs out to whichever side has the room.
|
|
1325
|
+
*/
|
|
1326
|
+
const fitAngledLeader = (anchorX, anchorY, desired, width, height, radius = 0) => {
|
|
1327
|
+
const canvas = this.viewer.canvas;
|
|
1328
|
+
const above = Math.max(0, anchorY - height / 2);
|
|
1329
|
+
const below = Math.max(0, canvas.clientHeight - anchorY - height / 2);
|
|
1330
|
+
const upwards = above >= Math.max(radius ? radius + 4 : 0, Math.min(8, desired)) || above >= below;
|
|
1331
|
+
const length = Math.min(desired, upwards ? above : below);
|
|
1332
|
+
const endY = anchorY + (upwards ? -length : length);
|
|
1333
|
+
const run = Math.max(ANGLED_LEADER_RUN, radius + 4);
|
|
1334
|
+
const rightwards = anchorX + run + width <= canvas.clientWidth || anchorX - run - width < 0;
|
|
1335
|
+
return {
|
|
1336
|
+
x: Math.max(0, Math.min(rightwards ? anchorX + run : anchorX - run - width, canvas.clientWidth - width)),
|
|
1337
|
+
y: Math.max(0, Math.min(endY - height / 2, canvas.clientHeight - height)), endY,
|
|
1338
|
+
run, side: (rightwards ? "right" : "left")
|
|
1339
|
+
};
|
|
1340
|
+
};
|
|
1260
1341
|
let cursorMotion = this.cursorMotion;
|
|
1261
1342
|
const project = () => {
|
|
1262
1343
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
@@ -1398,7 +1479,14 @@ var EntityLabel;
|
|
|
1398
1479
|
y -= height / 2;
|
|
1399
1480
|
}
|
|
1400
1481
|
// Membership uses the unclamped source footprint, never the summary's changing dimensions.
|
|
1401
|
-
|
|
1482
|
+
let leaderRun;
|
|
1483
|
+
let leaderSide;
|
|
1484
|
+
if (leader && angled) {
|
|
1485
|
+
const fit = fitAngledLeader(anchorX, anchorY, leaderLength, width, height);
|
|
1486
|
+
({ x, y } = fit);
|
|
1487
|
+
({ run: leaderRun, side: leaderSide } = fit);
|
|
1488
|
+
}
|
|
1489
|
+
else if (leader)
|
|
1402
1490
|
({ x, y } = fitLeader(anchorX, anchorY, leaderLength, width, height));
|
|
1403
1491
|
const bounds = clusterBounds || { x, y, width, height };
|
|
1404
1492
|
if (!leader && (bounds.x + bounds.width < 0 || bounds.y + bounds.height < 0 || bounds.x > this.viewer.canvas.clientWidth || bounds.y > this.viewer.canvas.clientHeight)) {
|
|
@@ -1413,20 +1501,21 @@ var EntityLabel;
|
|
|
1413
1501
|
extendedGeometry: visual instanceof Cesium.Entity && Boolean(visual.polygon || visual.polyline || visual.corridor),
|
|
1414
1502
|
viewportWidth: this.viewer.canvas.clientWidth,
|
|
1415
1503
|
id: this.id, entityKey: ((_s = this.rego) === null || _s === void 0 ? void 0 : _s.entityId) ? JSON.stringify([this.rego.entityId, this.rego.menuItemId || "", this.Transient && !this.Persistent ? "hover" : ""]) : undefined,
|
|
1416
|
-
entityId: (_t = this.rego) === null || _t === void 0 ? void 0 : _t.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, distance,
|
|
1504
|
+
entityId: (_t = this.rego) === null || _t === void 0 ? void 0 : _t.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, leaderRun, leaderSide, distance,
|
|
1417
1505
|
// Priority shows the hovered member individually without dragging its cluster along.
|
|
1418
1506
|
opacity, priority: hover || cursorAmount > 0 || (state === null || state === void 0 ? void 0 : state.highlighted) ? 1 : 0, options: this.options, text: originalText, clusterBounds
|
|
1419
1507
|
};
|
|
1420
1508
|
};
|
|
1421
1509
|
let displacement = { x: 0, y: 0 };
|
|
1422
|
-
let displayedSummaryMore = false;
|
|
1423
1510
|
let nudge = { x: 0, y: 0, fromX: 0, fromY: 0, targetX: 0, targetY: 0, start: 0 };
|
|
1424
1511
|
const apply = (placement) => {
|
|
1425
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
1512
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
1426
1513
|
const show = (placement === null || placement === void 0 ? void 0 : placement.visible) && placement.opacity > 0;
|
|
1427
1514
|
clickEntityIds = show ? placement.entityIds : [];
|
|
1428
1515
|
ele.style.visibility = show ? "visible" : "hidden";
|
|
1429
1516
|
lineEle.style.display = show && leader ? "block" : "none";
|
|
1517
|
+
if (runEle)
|
|
1518
|
+
runEle.style.display = show && leader ? "block" : "none";
|
|
1430
1519
|
this.anchor.style.display = show && leader ? "block" : "none";
|
|
1431
1520
|
if (!show) {
|
|
1432
1521
|
displacement = { x: 0, y: 0 };
|
|
@@ -1437,17 +1526,8 @@ var EntityLabel;
|
|
|
1437
1526
|
return;
|
|
1438
1527
|
}
|
|
1439
1528
|
const displayText = (_a = placement.text) !== null && _a !== void 0 ? _a : originalText;
|
|
1440
|
-
|
|
1441
|
-
if (textElement && (textElement.textContent !== displayText + (summaryMore ? "\n…" : "") || displayedSummaryMore !== summaryMore)) {
|
|
1529
|
+
if (textElement && textElement.textContent !== displayText) {
|
|
1442
1530
|
textElement.textContent = displayText;
|
|
1443
|
-
if (summaryMore) {
|
|
1444
|
-
const more = document.createElement("span");
|
|
1445
|
-
more.className = "entity-label-more";
|
|
1446
|
-
more.style.opacity = "0.65";
|
|
1447
|
-
more.textContent = "\n…";
|
|
1448
|
-
textElement.appendChild(more);
|
|
1449
|
-
}
|
|
1450
|
-
displayedSummaryMore = summaryMore;
|
|
1451
1531
|
// Measure the summary's footprint next frame without replacing each member's source text.
|
|
1452
1532
|
this.viewer.scene.requestRender();
|
|
1453
1533
|
}
|
|
@@ -1465,6 +1545,7 @@ var EntityLabel;
|
|
|
1465
1545
|
// The badge participates in layout, so its new width needs another measurement.
|
|
1466
1546
|
this.viewer.scene.requestRender();
|
|
1467
1547
|
}
|
|
1548
|
+
fitIconBackground === null || fitIconBackground === void 0 ? void 0 : fitIconBackground();
|
|
1468
1549
|
if (iconContainer) {
|
|
1469
1550
|
const badgeWidth = countElement.offsetWidth;
|
|
1470
1551
|
const iconWidth = iconElement.offsetWidth;
|
|
@@ -1472,7 +1553,9 @@ var EntityLabel;
|
|
|
1472
1553
|
const clearance = badgeWidth ? (narrow ? badgeWidth / 2 + 2 : Math.max(0, badgeWidth / 2 - iconWidth / 4)) : 0;
|
|
1473
1554
|
countElement.style.left = `calc(100% + ${clearance}px)`;
|
|
1474
1555
|
// Reserve the badge overhang so adjacent text and viewport edges remain clear.
|
|
1475
|
-
|
|
1556
|
+
const overhang = countElement.offsetHeight / 2;
|
|
1557
|
+
iconContainer.style.marginTop = badgeBelow ? "0px" : `${overhang}px`;
|
|
1558
|
+
iconContainer.style.marginBottom = badgeBelow ? `${overhang}px` : "0px";
|
|
1476
1559
|
iconContainer.style.marginRight = `${badgeWidth / 2 + clearance}px`;
|
|
1477
1560
|
}
|
|
1478
1561
|
// Summary and badge changes must fit on their first visible frame, including after resize.
|
|
@@ -1516,19 +1599,26 @@ var EntityLabel;
|
|
|
1516
1599
|
sharedRing.animation = ringAnimation;
|
|
1517
1600
|
}
|
|
1518
1601
|
const radius = ringAnimation.inner > 0 ? ringAnimation.outer : 0;
|
|
1519
|
-
const stem = (leader ? fitLeader(frame.anchorX, frame.anchorY, Math.max(frame.leaderLength, radius ? radius + 4 : 0), ele.offsetWidth / coordinates.scaleX, ele.offsetHeight / coordinates.scaleY, radius) : undefined);
|
|
1602
|
+
const stem = (leader ? (angled ? fitAngledLeader : fitLeader)(frame.anchorX, frame.anchorY, Math.max(frame.leaderLength, radius ? radius + 4 : 0), ele.offsetWidth / coordinates.scaleX, ele.offsetHeight / coordinates.scaleY, radius) : undefined);
|
|
1520
1603
|
const position = { x: (stem || frame).x, y: (stem || frame).y };
|
|
1521
1604
|
const width = ele.offsetWidth / coordinates.scaleX;
|
|
1522
1605
|
const height = ele.offsetHeight / coordinates.scaleY;
|
|
1523
|
-
if (leader &&
|
|
1606
|
+
if (leader && angled) {
|
|
1607
|
+
// The declutter owns the side; the fit only says which one had the room to begin with.
|
|
1608
|
+
const run = Math.max(ANGLED_LEADER_RUN, radius + 4);
|
|
1609
|
+
const side = (_l = (_k = placement.textSide) !== null && _k !== void 0 ? _k : frame.leaderSide) !== null && _l !== void 0 ? _l : "right";
|
|
1610
|
+
const beside = side === "left" ? frame.anchorX - run - width : frame.anchorX + run;
|
|
1611
|
+
position.x = Math.max(0, Math.min(beside, this.viewer.canvas.clientWidth - width));
|
|
1612
|
+
}
|
|
1613
|
+
else if (leader && placement.textSide === "left") {
|
|
1524
1614
|
position.x = Math.max(0, Math.min(frame.anchorX - width, this.viewer.canvas.clientWidth - width));
|
|
1525
1615
|
}
|
|
1526
|
-
const gap = (
|
|
1616
|
+
const gap = (_o = (_m = this.options.pointerAvoidance) === null || _m === void 0 ? void 0 : _m.gap) !== null && _o !== void 0 ? _o : 12;
|
|
1527
1617
|
const containsPointer = (x, y, margin) => {
|
|
1528
1618
|
return pointer && pointer.x >= x - margin && pointer.x <= x + width + margin && pointer.y >= y - margin && pointer.y <= y + height + margin;
|
|
1529
1619
|
};
|
|
1530
1620
|
const passive = !selectOnClick || !this.visualRegister;
|
|
1531
|
-
if (passive && ((
|
|
1621
|
+
if (passive && ((_p = this.options.pointerAvoidance) === null || _p === void 0 ? void 0 : _p.enabled) !== false && pointer &&
|
|
1532
1622
|
(containsPointer(position.x, position.y, gap) || containsPointer(position.x + displacement.x, position.y + displacement.y, gap))) {
|
|
1533
1623
|
if (containsPointer(position.x + displacement.x, position.y + displacement.y, 0)) {
|
|
1534
1624
|
// Choose against the original box and retain the offset until the pointer leaves both boxes.
|
|
@@ -1546,7 +1636,7 @@ var EntityLabel;
|
|
|
1546
1636
|
else {
|
|
1547
1637
|
displacement = { x: 0, y: 0 };
|
|
1548
1638
|
}
|
|
1549
|
-
const nudgeDuration = (
|
|
1639
|
+
const nudgeDuration = (_r = (_q = this.options.pointerAvoidance) === null || _q === void 0 ? void 0 : _q.transitionDuration) !== null && _r !== void 0 ? _r : 200;
|
|
1550
1640
|
const animateNudge = () => {
|
|
1551
1641
|
const progress = now < nudge.start ? 0 : nudgeDuration > 0 ? Math.min(1, (now - nudge.start) / nudgeDuration) : 1;
|
|
1552
1642
|
const eased = progress * progress * (3 - 2 * progress);
|
|
@@ -1562,7 +1652,7 @@ var EntityLabel;
|
|
|
1562
1652
|
fromY: nudge.y,
|
|
1563
1653
|
targetX: displacement.x,
|
|
1564
1654
|
targetY: displacement.y,
|
|
1565
|
-
start: now + ((
|
|
1655
|
+
start: now + ((_t = (_s = this.options.pointerAvoidance) === null || _s === void 0 ? void 0 : _s.delay) !== null && _t !== void 0 ? _t : 180)
|
|
1566
1656
|
};
|
|
1567
1657
|
}
|
|
1568
1658
|
if (animateNudge() < 1 && (nudge.fromX !== nudge.targetX || nudge.fromY !== nudge.targetY)) {
|
|
@@ -1574,7 +1664,7 @@ var EntityLabel;
|
|
|
1574
1664
|
ele.style.top = `${coordinates.y + position.y * coordinates.scaleY}px`;
|
|
1575
1665
|
const clickTarget = content.querySelector('[role="button"]');
|
|
1576
1666
|
if (clickTarget) {
|
|
1577
|
-
clickTarget.setAttribute("aria-label", placement.members.length ? `Select ${placement.entityIds.length} entities` : `Select ${(
|
|
1667
|
+
clickTarget.setAttribute("aria-label", placement.members.length ? `Select ${placement.entityIds.length} entities` : `Select ${(_v = (_u = this.options.text) !== null && _u !== void 0 ? _u : text) !== null && _v !== void 0 ? _v : (_w = this.rego) === null || _w === void 0 ? void 0 : _w.entityId}`);
|
|
1578
1668
|
}
|
|
1579
1669
|
if (leader) {
|
|
1580
1670
|
const nodeRadius = ringAnimation.outer;
|
|
@@ -1597,8 +1687,13 @@ var EntityLabel;
|
|
|
1597
1687
|
anchor.style.opacity = String(opacity * (normalLeader ? 1 : cursorMotion.amount));
|
|
1598
1688
|
anchor.style.zIndex = String(placement.zIndex);
|
|
1599
1689
|
// The stem starts at the rim, never across the transparent centre, even after passive displacement.
|
|
1600
|
-
const
|
|
1601
|
-
const
|
|
1690
|
+
const straightX = Math.max(position.x, Math.min(frame.anchorX, position.x + width));
|
|
1691
|
+
const straightY = frame.anchorY < position.y ? position.y : frame.anchorY > position.y + height ? position.y + height : frame.anchorY;
|
|
1692
|
+
const beside = angled && (frame.anchorX < position.x || frame.anchorX > position.x + width);
|
|
1693
|
+
const elbowY = position.y + height / 2;
|
|
1694
|
+
const endX = beside ? frame.anchorX : straightX;
|
|
1695
|
+
const endY = beside ? elbowY : straightY;
|
|
1696
|
+
const runToX = frame.anchorX < position.x ? position.x : position.x + width;
|
|
1602
1697
|
const dx = endX - frame.anchorX, dy = endY - frame.anchorY;
|
|
1603
1698
|
const length = Math.hypot(dx, dy);
|
|
1604
1699
|
const leaderAngle = Math.atan2(dy, dx);
|
|
@@ -1609,13 +1704,13 @@ var EntityLabel;
|
|
|
1609
1704
|
// Keep the stem inside the 126-degree arc, away from antialiased endpoints.
|
|
1610
1705
|
const arcFraction = 0.35;
|
|
1611
1706
|
const rotationLimit = Math.PI * arcFraction - Math.PI / 30;
|
|
1612
|
-
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((
|
|
1707
|
+
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((_x = ringAnimation.arcOffset) !== null && _x !== void 0 ? _x : 0);
|
|
1613
1708
|
const targetOpen = cursorMotion.target || (hovered && (ring === null || ring === void 0 ? void 0 : ring.enabled) !== false && targetRadius > 0) ? 1 : 0;
|
|
1614
|
-
const elapsed = Math.min(32, Math.max(0, now - ((
|
|
1709
|
+
const elapsed = Math.min(32, Math.max(0, now - ((_y = ringAnimation.arcTime) !== null && _y !== void 0 ? _y : now)));
|
|
1615
1710
|
const blend = duration > 0 ? 1 - Math.exp(-elapsed / (duration / 3)) : 1;
|
|
1616
1711
|
const approach = (value, target) => Math.abs(value - target) < 0.001 ? target : value + (target - value) * blend;
|
|
1617
|
-
ringAnimation.arcOffset = approach((
|
|
1618
|
-
ringAnimation.arcOpen = approach((
|
|
1712
|
+
ringAnimation.arcOffset = approach((_z = ringAnimation.arcOffset) !== null && _z !== void 0 ? _z : 0, targetOffset);
|
|
1713
|
+
ringAnimation.arcOpen = approach((_0 = ringAnimation.arcOpen) !== null && _0 !== void 0 ? _0 : 0, targetOpen);
|
|
1619
1714
|
ringAnimation.arcTime = now;
|
|
1620
1715
|
if (ringAnimation.arcOffset !== targetOffset || ringAnimation.arcOpen !== targetOpen) {
|
|
1621
1716
|
this.viewer.scene.requestRender();
|
|
@@ -1627,17 +1722,27 @@ var EntityLabel;
|
|
|
1627
1722
|
const cut = Math.min(radius, length);
|
|
1628
1723
|
const startX = frame.anchorX + (length ? dx / length * cut : 0);
|
|
1629
1724
|
const startY = frame.anchorY + (length ? dy / length * cut : 0);
|
|
1630
|
-
const
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1725
|
+
const draw = (element, fromX, fromY, toX, toY) => {
|
|
1726
|
+
const screenDx = (toX - fromX) * coordinates.scaleX;
|
|
1727
|
+
const screenDy = (toY - fromY) * coordinates.scaleY;
|
|
1728
|
+
element.style.width = `${2 * coordinates.scaleX}px`;
|
|
1729
|
+
element.style.left = `${coordinates.x + (fromX - 1) * coordinates.scaleX}px`;
|
|
1730
|
+
element.style.top = `${coordinates.y + fromY * coordinates.scaleY}px`;
|
|
1731
|
+
element.style.height = `${Math.hypot(screenDx, screenDy)}px`;
|
|
1732
|
+
element.style.transform = `rotate(${Math.atan2(screenDy, screenDx) - Math.PI / 2}rad)`;
|
|
1733
|
+
element.style.boxShadow = radius ? "none" : "0 0 5px rgba(0, 0, 0, 0.3)";
|
|
1734
|
+
element.style.transformOrigin = "top center";
|
|
1735
|
+
element.style.opacity = String(opacity * (normalLeader ? 1 : cursorMotion.amount));
|
|
1736
|
+
element.style.zIndex = String(placement.zIndex);
|
|
1737
|
+
};
|
|
1738
|
+
draw(lineEle, startX, startY, endX, endY);
|
|
1739
|
+
if (runEle) {
|
|
1740
|
+
// Overlap the corner by the stem's own width so the elbow has no notch in it.
|
|
1741
|
+
const overlap = frame.anchorX < runToX ? -1 : 1;
|
|
1742
|
+
runEle.style.display = beside ? "block" : "none";
|
|
1743
|
+
if (beside)
|
|
1744
|
+
draw(runEle, endX + overlap, endY, runToX, endY);
|
|
1745
|
+
}
|
|
1641
1746
|
}
|
|
1642
1747
|
};
|
|
1643
1748
|
ele.style.display = "flex";
|
|
@@ -1662,7 +1767,7 @@ var EntityLabel;
|
|
|
1662
1767
|
* Removes label from the viewer and unsubscribes from events.
|
|
1663
1768
|
*/
|
|
1664
1769
|
removeLabel() {
|
|
1665
|
-
var _a;
|
|
1770
|
+
var _a, _b;
|
|
1666
1771
|
(_a = this.anchor) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1667
1772
|
this.anchor = null;
|
|
1668
1773
|
if (this.label &&
|
|
@@ -1674,6 +1779,8 @@ var EntityLabel;
|
|
|
1674
1779
|
this.line.parentElement.removeChild(this.line);
|
|
1675
1780
|
this.line = null;
|
|
1676
1781
|
}
|
|
1782
|
+
(_b = this.leaderRun) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1783
|
+
this.leaderRun = null;
|
|
1677
1784
|
if (this.renderRemoval) {
|
|
1678
1785
|
this.renderRemoval();
|
|
1679
1786
|
this.renderRemoval = null;
|