bruce-cesium 7.3.9 โ 7.4.1
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 +2655 -603
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +2654 -600
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +8 -2
- package/dist/lib/bruce-cesium.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label-group.js +538 -0
- package/dist/lib/rendering/render-managers/common/entity-label-group.js.map +1 -0
- package/dist/lib/rendering/render-managers/common/entity-label.js +1213 -155
- package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/point-clustering-core.js +85 -0
- package/dist/lib/rendering/render-managers/common/point-clustering-core.js.map +1 -0
- package/dist/lib/rendering/render-managers/common/point-clustering.js +566 -419
- package/dist/lib/rendering/render-managers/common/point-clustering.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js +2 -2
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/visuals-register.js +273 -24
- package/dist/lib/rendering/visuals-register.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +4 -1
- package/dist/types/rendering/render-managers/common/entity-label-group.d.ts +109 -0
- package/dist/types/rendering/render-managers/common/entity-label.d.ts +138 -1
- package/dist/types/rendering/render-managers/common/point-clustering-core.d.ts +17 -0
- package/dist/types/rendering/render-managers/common/point-clustering.d.ts +37 -72
- package/dist/types/rendering/visuals-register.d.ts +43 -2
- package/package.json +1 -1
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -5283,6 +5283,86 @@
|
|
|
5283
5283
|
return gate;
|
|
5284
5284
|
}
|
|
5285
5285
|
|
|
5286
|
+
/*
|
|
5287
|
+
* Status semantics are shared by label and scene-entity clusters; opaque image pixels are not inferred.
|
|
5288
|
+
* A bit jank but helps keep current 'important' labels higher than others.
|
|
5289
|
+
*/
|
|
5290
|
+
function GetClusterIconPriority(options) {
|
|
5291
|
+
if (Number.isFinite(options === null || options === void 0 ? void 0 : options.iconPriority)) {
|
|
5292
|
+
return options.iconPriority;
|
|
5293
|
+
}
|
|
5294
|
+
const statusPriority = (value) => {
|
|
5295
|
+
const tokens = value.toLowerCase().split(/[^a-z0-9]+/);
|
|
5296
|
+
if (tokens.some(token => ["critical", "fatal", "error", "fault", "failed", "alarm", "danger", "red"].includes(token))) {
|
|
5297
|
+
return 3;
|
|
5298
|
+
}
|
|
5299
|
+
if (tokens.some(token => ["warning", "warn", "degraded", "amber", "orange", "yellow"].includes(token))) {
|
|
5300
|
+
return 2;
|
|
5301
|
+
}
|
|
5302
|
+
if (tokens.some(token => ["unknown", "offline"].includes(token))) {
|
|
5303
|
+
return 1;
|
|
5304
|
+
}
|
|
5305
|
+
return 0;
|
|
5306
|
+
};
|
|
5307
|
+
if ((options === null || options === void 0 ? void 0 : options.iconStatus) != null) {
|
|
5308
|
+
return statusPriority(options.iconStatus);
|
|
5309
|
+
}
|
|
5310
|
+
const glyph = (options === null || options === void 0 ? void 0 : options.icon) || "";
|
|
5311
|
+
if (/[๐ด๐ฅโ๐จ]/u.test(glyph)) {
|
|
5312
|
+
return 3;
|
|
5313
|
+
}
|
|
5314
|
+
if (/[๐ ๐กโ ]/u.test(glyph)) {
|
|
5315
|
+
return 2;
|
|
5316
|
+
}
|
|
5317
|
+
let filename = "";
|
|
5318
|
+
if ((options === null || options === void 0 ? void 0 : options.iconUrl) && !/^(data|blob):/i.test(options.iconUrl)) {
|
|
5319
|
+
try {
|
|
5320
|
+
filename = decodeURIComponent(new URL(options.iconUrl, "https://label.invalid").pathname.split("/").pop());
|
|
5321
|
+
}
|
|
5322
|
+
catch {
|
|
5323
|
+
// Ignore malformed URLs when inferring status.
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
return Math.max(statusPriority(glyph), statusPriority(filename));
|
|
5327
|
+
}
|
|
5328
|
+
/*
|
|
5329
|
+
* Groups eligible neighbours around stable representatives without coupling membership to its renderer.
|
|
5330
|
+
*/
|
|
5331
|
+
function ClusterItems(params) {
|
|
5332
|
+
const eligible = new Map();
|
|
5333
|
+
for (const item of params.items) {
|
|
5334
|
+
if (!params.eligible || params.eligible(item)) {
|
|
5335
|
+
eligible.set(params.id(item), item);
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
const assigned = new Set();
|
|
5339
|
+
const result = [];
|
|
5340
|
+
const minimum = Math.max(2, params.minSize || 2);
|
|
5341
|
+
for (const [id, item] of eligible) {
|
|
5342
|
+
if (assigned.has(id)) {
|
|
5343
|
+
continue;
|
|
5344
|
+
}
|
|
5345
|
+
const members = new Map([[id, item]]);
|
|
5346
|
+
for (const neighbour of params.neighbours(item)) {
|
|
5347
|
+
const key = params.id(neighbour);
|
|
5348
|
+
if (eligible.has(key) && !assigned.has(key)) {
|
|
5349
|
+
members.set(key, eligible.get(key));
|
|
5350
|
+
}
|
|
5351
|
+
}
|
|
5352
|
+
if (members.size < minimum) {
|
|
5353
|
+
continue;
|
|
5354
|
+
}
|
|
5355
|
+
for (const key of members.keys()) {
|
|
5356
|
+
assigned.add(key);
|
|
5357
|
+
}
|
|
5358
|
+
result.push({
|
|
5359
|
+
representative: item,
|
|
5360
|
+
members: Array.from(members.values())
|
|
5361
|
+
});
|
|
5362
|
+
}
|
|
5363
|
+
return result;
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5286
5366
|
/**
|
|
5287
5367
|
* Returns cesium property's value.
|
|
5288
5368
|
* This will check if it's one that changes over time, or just a fixed value.
|
|
@@ -5301,10 +5381,564 @@
|
|
|
5301
5381
|
return obj;
|
|
5302
5382
|
}
|
|
5303
5383
|
(function (EntityLabel) {
|
|
5384
|
+
const ICON_BACKGROUND_BLEND = 0.8;
|
|
5385
|
+
const ICON_BACKGROUND_ALPHA = 0.45;
|
|
5386
|
+
const TEXT_MAX_WIDTH = 200;
|
|
5304
5387
|
// Key where the label instance is stored within the cesium entity.
|
|
5305
5388
|
// Eg: rego[ATTACH_KEY] = new EntityLabel(...);
|
|
5306
5389
|
EntityLabel.ATTACH_KEY = "nextspace-navigator-entity-label";
|
|
5390
|
+
/*
|
|
5391
|
+
* Indexes screen rectangles so sparse scenes do not compare every label with every other label.
|
|
5392
|
+
*/
|
|
5393
|
+
class ScreenIndex {
|
|
5394
|
+
constructor() {
|
|
5395
|
+
this.cells = new Map();
|
|
5396
|
+
this.large = [];
|
|
5397
|
+
this.all = [];
|
|
5398
|
+
}
|
|
5399
|
+
keys(frame, padding = 0) {
|
|
5400
|
+
const x0 = Math.floor((frame.x - padding) / 64);
|
|
5401
|
+
const y0 = Math.floor((frame.y - padding) / 64);
|
|
5402
|
+
const x1 = Math.floor((frame.x + frame.width + padding) / 64);
|
|
5403
|
+
const y1 = Math.floor((frame.y + frame.height + padding) / 64);
|
|
5404
|
+
if ((x1 - x0 + 1) * (y1 - y0 + 1) > 4096) {
|
|
5405
|
+
return null;
|
|
5406
|
+
}
|
|
5407
|
+
const keys = [];
|
|
5408
|
+
for (let x = x0; x <= x1; x++) {
|
|
5409
|
+
for (let y = y0; y <= y1; y++) {
|
|
5410
|
+
keys.push(`${x},${y}`);
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
return keys;
|
|
5414
|
+
}
|
|
5415
|
+
Add(frame) {
|
|
5416
|
+
this.all.push(frame);
|
|
5417
|
+
const keys = this.keys(frame);
|
|
5418
|
+
if (!keys) {
|
|
5419
|
+
this.large.push(frame);
|
|
5420
|
+
return;
|
|
5421
|
+
}
|
|
5422
|
+
for (const key of keys) {
|
|
5423
|
+
if (!this.cells.has(key)) {
|
|
5424
|
+
this.cells.set(key, []);
|
|
5425
|
+
}
|
|
5426
|
+
this.cells.get(key).push(frame);
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
Query(frame, padding = 0) {
|
|
5430
|
+
const keys = this.keys(frame, padding);
|
|
5431
|
+
const found = new Set(keys ? this.large : this.all);
|
|
5432
|
+
for (const key of keys || []) {
|
|
5433
|
+
for (const item of this.cells.get(key) || []) {
|
|
5434
|
+
found.add(item);
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
return (Array.from(found).filter(other => frame.x <= other.x + other.width + padding && frame.x + frame.width + padding >= other.x &&
|
|
5438
|
+
frame.y <= other.y + other.height + padding && frame.y + frame.height + padding >= other.y));
|
|
5439
|
+
}
|
|
5440
|
+
HasOverlap(frame) {
|
|
5441
|
+
var _a;
|
|
5442
|
+
const intersects = (other) => (frame.x <= other.x + other.width && frame.x + frame.width >= other.x &&
|
|
5443
|
+
frame.y <= other.y + other.height && frame.y + frame.height >= other.y);
|
|
5444
|
+
const keys = this.keys(frame);
|
|
5445
|
+
if ((keys ? this.large : this.all).some(intersects)) {
|
|
5446
|
+
return true;
|
|
5447
|
+
}
|
|
5448
|
+
for (const key of keys || []) {
|
|
5449
|
+
if ((_a = this.cells.get(key)) === null || _a === void 0 ? void 0 : _a.some(intersects)) {
|
|
5450
|
+
return true;
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
return false;
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
/*
|
|
5457
|
+
* Includes the stem in collision checks without treating two crossing stems as text occlusion.
|
|
5458
|
+
*/
|
|
5459
|
+
function leaderBounds(frame) {
|
|
5460
|
+
if (!frame.hasLeader || !Number.isFinite(frame.anchorX) || !Number.isFinite(frame.anchorY)) {
|
|
5461
|
+
return undefined;
|
|
5462
|
+
}
|
|
5463
|
+
const endX = Math.max(frame.x, Math.min(frame.anchorX, frame.x + frame.width));
|
|
5464
|
+
const endY = Math.max(frame.y, Math.min(frame.anchorY, frame.y + frame.height));
|
|
5465
|
+
if (Math.hypot(frame.anchorX - endX, frame.anchorY - endY) < .01) {
|
|
5466
|
+
return undefined;
|
|
5467
|
+
}
|
|
5468
|
+
return {
|
|
5469
|
+
...frame,
|
|
5470
|
+
x: Math.min(frame.anchorX, endX) - 1,
|
|
5471
|
+
y: Math.min(frame.anchorY, endY) + .01,
|
|
5472
|
+
width: Math.abs(frame.anchorX - endX) + 2,
|
|
5473
|
+
height: Math.max(0, Math.abs(frame.anchorY - endY) - .02)
|
|
5474
|
+
};
|
|
5475
|
+
}
|
|
5476
|
+
/*
|
|
5477
|
+
* Remembers sides, never rendered positions: its own output cannot trigger another layout pass.
|
|
5478
|
+
*/
|
|
5479
|
+
class PlacementMemory {
|
|
5480
|
+
constructor() {
|
|
5481
|
+
this.previous = new Map();
|
|
5482
|
+
this.nextOrder = 0;
|
|
5483
|
+
}
|
|
5484
|
+
Resolve(frames) {
|
|
5485
|
+
var _a, _b;
|
|
5486
|
+
const live = new Set(frames.map(frame => frame.id));
|
|
5487
|
+
const moved = (frame) => {
|
|
5488
|
+
var _a;
|
|
5489
|
+
const old = (_a = this.previous.get(frame.id)) === null || _a === void 0 ? void 0 : _a.frame;
|
|
5490
|
+
return (!old ||
|
|
5491
|
+
old.transient !== frame.transient || old.canFlip !== frame.canFlip ||
|
|
5492
|
+
Math.hypot(frame.x - old.x, frame.y - old.y) >= 24 ||
|
|
5493
|
+
Math.abs(frame.width - old.width) >= 8 || Math.abs(frame.height - old.height) >= 8);
|
|
5494
|
+
};
|
|
5495
|
+
const persistent = frames.filter(frame => !frame.transient);
|
|
5496
|
+
const changes = (persistent.filter(moved).length +
|
|
5497
|
+
Array.from(this.previous.values()).filter(old => !old.frame.transient && !live.has(old.frame.id)).length);
|
|
5498
|
+
// A hover or one arrival cannot rearrange incumbents; a substantial batch/camera change can.
|
|
5499
|
+
const restructure = this.previous.size > 0 && changes >= Math.max(2, Math.ceil(persistent.length * 0.3));
|
|
5500
|
+
const fixed = (frame) => !restructure && !frame.transient && this.previous.has(frame.id) && !moved(frame);
|
|
5501
|
+
const ordered = ([...frames].sort((a, b) => {
|
|
5502
|
+
var _a, _b, _c, _d;
|
|
5503
|
+
return Number(fixed(b)) - Number(fixed(a)) ||
|
|
5504
|
+
Number(Boolean(a.transient)) - Number(Boolean(b.transient)) ||
|
|
5505
|
+
((_b = (_a = this.previous.get(a.id)) === null || _a === void 0 ? void 0 : _a.order) !== null && _b !== void 0 ? _b : Infinity) - ((_d = (_c = this.previous.get(b.id)) === null || _c === void 0 ? void 0 : _c.order) !== null && _d !== void 0 ? _d : Infinity) ||
|
|
5506
|
+
a.depth - b.depth || a.id.localeCompare(b.id);
|
|
5507
|
+
}));
|
|
5508
|
+
const text = new ScreenIndex(), leaders = new ScreenIndex();
|
|
5509
|
+
const placed = new Map();
|
|
5510
|
+
const next = new Map();
|
|
5511
|
+
const candidate = (frame, side) => {
|
|
5512
|
+
var _a;
|
|
5513
|
+
return (side === "left" && frame.canFlip ?
|
|
5514
|
+
{ ...frame, x: Math.max(0, Math.min(frame.anchorX - frame.width, ((_a = frame.viewportWidth) !== null && _a !== void 0 ? _a : Infinity) - frame.width)) } :
|
|
5515
|
+
frame);
|
|
5516
|
+
};
|
|
5517
|
+
const score = (frame, padding = 0) => {
|
|
5518
|
+
const box = {
|
|
5519
|
+
...frame,
|
|
5520
|
+
x: frame.x - padding + .01,
|
|
5521
|
+
y: frame.y - padding + .01,
|
|
5522
|
+
width: Math.max(0, frame.width + padding * 2 - .02),
|
|
5523
|
+
height: Math.max(0, frame.height + padding * 2 - .02)
|
|
5524
|
+
};
|
|
5525
|
+
const stem = leaderBounds(frame);
|
|
5526
|
+
return (Number(text.HasOverlap(box)) * 4 + Number(leaders.HasOverlap(box)) +
|
|
5527
|
+
Number(Boolean(stem && text.HasOverlap(stem))));
|
|
5528
|
+
};
|
|
5529
|
+
for (const frame of ordered) {
|
|
5530
|
+
const old = this.previous.get(frame.id);
|
|
5531
|
+
let side = frame.canFlip ? (_a = old === null || old === void 0 ? void 0 : old.side) !== null && _a !== void 0 ? _a : "right" : "right";
|
|
5532
|
+
let chosen = candidate(frame, side);
|
|
5533
|
+
if (!fixed(frame) && frame.canFlip) {
|
|
5534
|
+
const otherSide = side === "left" ? "right" : "left";
|
|
5535
|
+
const other = candidate(frame, otherSide);
|
|
5536
|
+
// An established side only changes when the alternative has a little breathing room.
|
|
5537
|
+
if (score(other, old ? 4 : 0) < score(chosen)) {
|
|
5538
|
+
side = otherSide;
|
|
5539
|
+
chosen = other;
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
placed.set(frame.id, { frame: chosen, side });
|
|
5543
|
+
next.set(frame.id, { frame: fixed(frame) ? old.frame : { ...frame }, side, order: (_b = old === null || old === void 0 ? void 0 : old.order) !== null && _b !== void 0 ? _b : this.nextOrder++ });
|
|
5544
|
+
text.Add(chosen);
|
|
5545
|
+
const stem = leaderBounds(chosen);
|
|
5546
|
+
if (stem) {
|
|
5547
|
+
leaders.Add(stem);
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
this.previous = next;
|
|
5551
|
+
return placed;
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
EntityLabel.PlacementMemory = PlacementMemory;
|
|
5555
|
+
/*
|
|
5556
|
+
* Prefer declared semantics; only infers from recognisable glyphs and filename tokens, never image pixels.
|
|
5557
|
+
*/
|
|
5558
|
+
EntityLabel.IconPriority = GetClusterIconPriority;
|
|
5559
|
+
/*
|
|
5560
|
+
* Resolves clustering and stable text placement before depth fading; highlighted labels receive priority.
|
|
5561
|
+
*/
|
|
5562
|
+
function Layout(input, memory = new PlacementMemory()) {
|
|
5563
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5564
|
+
const frames = input.filter(frame => [frame.x, frame.y, frame.width, frame.height, frame.depth].every(Number.isFinite))
|
|
5565
|
+
.sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.depth - b.depth || a.id.localeCompare(b.id));
|
|
5566
|
+
const result = new Map();
|
|
5567
|
+
const entityKeys = new Set();
|
|
5568
|
+
const groups = new Map();
|
|
5569
|
+
for (const frame of frames) {
|
|
5570
|
+
const duplicate = frame.entityKey && entityKeys.has(frame.entityKey);
|
|
5571
|
+
result.set(frame.id, { frame, visible: !duplicate, opacity: frame.opacity, zIndex: 0, members: [], entityIds: frame.entityId ? [frame.entityId] : [] });
|
|
5572
|
+
if (duplicate) {
|
|
5573
|
+
continue;
|
|
5574
|
+
}
|
|
5575
|
+
if (frame.entityKey)
|
|
5576
|
+
entityKeys.add(frame.entityKey);
|
|
5577
|
+
if (!((_b = (_a = frame.options) === null || _a === void 0 ? void 0 : _a.cluster) === null || _b === void 0 ? void 0 : _b.enabled) || frame.priority > 0) {
|
|
5578
|
+
continue;
|
|
5579
|
+
}
|
|
5580
|
+
const key = JSON.stringify([frame.group || "", frame.options.presentation || "text"]);
|
|
5581
|
+
if (!groups.has(key)) {
|
|
5582
|
+
groups.set(key, []);
|
|
5583
|
+
}
|
|
5584
|
+
groups.get(key).push(frame);
|
|
5585
|
+
}
|
|
5586
|
+
for (const group of groups.values()) {
|
|
5587
|
+
// Summary and badge dimensions are output, never the next frame's membership input.
|
|
5588
|
+
const candidates = group.map(frame => frame.extendedGeometry && frame.canFlip &&
|
|
5589
|
+
frame.options.cluster.pixelRange == null ? { ...frame, x: frame.anchorX, y: frame.anchorY, width: 1, height: 1 } :
|
|
5590
|
+
frame.clusterBounds ? { ...frame, ...frame.clusterBounds } : frame);
|
|
5591
|
+
const index = new ScreenIndex();
|
|
5592
|
+
for (const frame of candidates) {
|
|
5593
|
+
index.Add(frame);
|
|
5594
|
+
}
|
|
5595
|
+
const clusters = ClusterItems({
|
|
5596
|
+
items: candidates,
|
|
5597
|
+
id: frame => frame.id,
|
|
5598
|
+
minSize: group[0].options.cluster.minSize,
|
|
5599
|
+
neighbours: frame => {
|
|
5600
|
+
var _a;
|
|
5601
|
+
return (index.Query(frame, (_a = frame.options.cluster.pixelRange) !== null && _a !== void 0 ? _a : (frame.options.presentation === "icon" ? 24 : 8)));
|
|
5602
|
+
}
|
|
5603
|
+
});
|
|
5604
|
+
for (const cluster of clusters) {
|
|
5605
|
+
let chosen = cluster.representative;
|
|
5606
|
+
if ((chosen.options.presentation || "text") !== "text" && chosen.options.cluster.representative !== "nearest") {
|
|
5607
|
+
let priority = EntityLabel.IconPriority(chosen.options);
|
|
5608
|
+
for (const member of cluster.members) {
|
|
5609
|
+
const candidate = EntityLabel.IconPriority(member.options);
|
|
5610
|
+
if (candidate > priority) {
|
|
5611
|
+
chosen = member;
|
|
5612
|
+
priority = candidate;
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5615
|
+
}
|
|
5616
|
+
const representative = result.get(chosen.id);
|
|
5617
|
+
representative.members = cluster.members.map(frame => frame.id);
|
|
5618
|
+
representative.entityIds = Array.from(new Set(cluster.members.map(frame => frame.entityId).filter(Boolean)));
|
|
5619
|
+
if (chosen.options.presentation !== "icon") {
|
|
5620
|
+
const values = new Set();
|
|
5621
|
+
const stableMembers = [...cluster.members].sort((a, b) => (a.entityKey || a.entityId || a.id).localeCompare(b.entityKey || b.entityId || b.id));
|
|
5622
|
+
for (const member of stableMembers) {
|
|
5623
|
+
const value = ((_e = (_c = member.text) !== null && _c !== void 0 ? _c : (_d = member.options) === null || _d === void 0 ? void 0 : _d.text) !== null && _e !== void 0 ? _e : "").replace(/\s+/g, " ").trim();
|
|
5624
|
+
if (value) {
|
|
5625
|
+
values.add(value);
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
if (values.size > 1) {
|
|
5629
|
+
const description = stableMembers.find(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()); });
|
|
5630
|
+
if (description) {
|
|
5631
|
+
representative.text = ((_f = description.text) !== null && _f !== void 0 ? _f : description.options.text).trim();
|
|
5632
|
+
representative.summaryMore = true;
|
|
5633
|
+
}
|
|
5634
|
+
else {
|
|
5635
|
+
const rows = Array.from(values).slice(0, 2);
|
|
5636
|
+
if (values.size > 2)
|
|
5637
|
+
rows.push(`+${values.size - 2} moreโฆ`);
|
|
5638
|
+
representative.text = rows.join("\n");
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
for (const frame of cluster.members) {
|
|
5643
|
+
if (frame !== chosen)
|
|
5644
|
+
result.get(frame.id).visible = false;
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
const placed = memory.Resolve(frames.filter(frame => result.get(frame.id).visible));
|
|
5649
|
+
const foreground = new ScreenIndex(), foregroundLeaders = new ScreenIndex();
|
|
5650
|
+
let zIndex = frames.length + 1;
|
|
5651
|
+
for (const original of frames) {
|
|
5652
|
+
const placement = result.get(original.id);
|
|
5653
|
+
if (!placement.visible) {
|
|
5654
|
+
continue;
|
|
5655
|
+
}
|
|
5656
|
+
const chosen = placed.get(original.id);
|
|
5657
|
+
const frame = placement.frame = chosen.frame;
|
|
5658
|
+
placement.textSide = chosen.side;
|
|
5659
|
+
const stem = leaderBounds(frame);
|
|
5660
|
+
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) };
|
|
5661
|
+
const overlap = foreground.HasOverlap(box) || foregroundLeaders.HasOverlap(box) || Boolean(stem && foreground.HasOverlap(stem));
|
|
5662
|
+
if (overlap) {
|
|
5663
|
+
placement.opacity *= Math.max(0, Math.min(1, (_h = (_g = frame.options) === null || _g === void 0 ? void 0 : _g.overlapOpacity) !== null && _h !== void 0 ? _h : 0.25));
|
|
5664
|
+
}
|
|
5665
|
+
placement.zIndex = zIndex--;
|
|
5666
|
+
foreground.Add(frame);
|
|
5667
|
+
if (stem) {
|
|
5668
|
+
foregroundLeaders.Add(stem);
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
return Array.from(result.values());
|
|
5672
|
+
}
|
|
5673
|
+
EntityLabel.Layout = Layout;
|
|
5674
|
+
const layers = new WeakMap();
|
|
5675
|
+
const containers = new WeakMap();
|
|
5676
|
+
/*
|
|
5677
|
+
* Moves the shared overlay without recreating labels or resolving their sources.
|
|
5678
|
+
*/
|
|
5679
|
+
function SetContainer(viewer, container) {
|
|
5680
|
+
const layer = layers.get(viewer);
|
|
5681
|
+
if (container && (container === (layer === null || layer === void 0 ? void 0 : layer.element) || (layer === null || layer === void 0 ? void 0 : layer.element.contains(container)))) {
|
|
5682
|
+
throw new Error("Label container cannot be inside the label overlay");
|
|
5683
|
+
}
|
|
5684
|
+
if (container) {
|
|
5685
|
+
containers.set(viewer, container);
|
|
5686
|
+
}
|
|
5687
|
+
else
|
|
5688
|
+
containers.delete(viewer);
|
|
5689
|
+
layer === null || layer === void 0 ? void 0 : layer.Move();
|
|
5690
|
+
}
|
|
5691
|
+
EntityLabel.SetContainer = SetContainer;
|
|
5692
|
+
/*
|
|
5693
|
+
* Owns one scene callback per viewer and separates projection/measurement from DOM writes.
|
|
5694
|
+
*/
|
|
5695
|
+
class Layer {
|
|
5696
|
+
constructor(viewer) {
|
|
5697
|
+
this.viewer = viewer;
|
|
5698
|
+
this.element = document.createElement("div");
|
|
5699
|
+
this.coordinates = { x: 0, y: 0, scaleX: 1, scaleY: 1 };
|
|
5700
|
+
this.participants = new Set();
|
|
5701
|
+
this.placementMemory = new PlacementMemory();
|
|
5702
|
+
this.forwardingWheel = false;
|
|
5703
|
+
this.pendingDrag = null;
|
|
5704
|
+
this.TrackPointer = (event) => {
|
|
5705
|
+
var _a, _b;
|
|
5706
|
+
if (event.pointerType && event.pointerType !== "mouse" && event.pointerType !== "pen")
|
|
5707
|
+
return;
|
|
5708
|
+
const rect = (_b = (_a = this.viewer.canvas).getBoundingClientRect) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
5709
|
+
if (!rect || event.clientX < rect.left || event.clientX >= rect.right || event.clientY < rect.top || event.clientY >= rect.bottom) {
|
|
5710
|
+
if (this.pointerClient)
|
|
5711
|
+
this.ClearPointer();
|
|
5712
|
+
return;
|
|
5713
|
+
}
|
|
5714
|
+
this.pointerClient = { x: event.clientX, y: event.clientY };
|
|
5715
|
+
this.viewer.scene.requestRender();
|
|
5716
|
+
};
|
|
5717
|
+
this.PointerOut = (event) => { if (!event.relatedTarget)
|
|
5718
|
+
this.ClearPointer(); };
|
|
5719
|
+
this.ClearPointer = () => {
|
|
5720
|
+
this.pointerClient = undefined;
|
|
5721
|
+
this.pointer = undefined;
|
|
5722
|
+
if (!this.viewer.isDestroyed()) {
|
|
5723
|
+
this.viewer.scene.requestRender();
|
|
5724
|
+
}
|
|
5725
|
+
};
|
|
5726
|
+
this.PreventNativeDrag = (event) => {
|
|
5727
|
+
event.preventDefault();
|
|
5728
|
+
};
|
|
5729
|
+
this.BeginDrag = (event) => {
|
|
5730
|
+
var _a, _b, _c;
|
|
5731
|
+
this.EndPendingDrag();
|
|
5732
|
+
const detection = Cesium.FeatureDetection;
|
|
5733
|
+
const target = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest) === null || _b === void 0 ? void 0 : _b.call(_a, '.entity-label [role="button"]');
|
|
5734
|
+
const canvas = this.viewer.canvas;
|
|
5735
|
+
if (event.defaultPrevented || event.button !== 0 || event.pointerType !== "mouse" ||
|
|
5736
|
+
((_c = detection.supportsPointerEvents) === null || _c === void 0 ? void 0 : _c.call(detection)) === false || !canvas.setPointerCapture || this.viewer.isDestroyed() ||
|
|
5737
|
+
!target || !this.element.contains(target) ||
|
|
5738
|
+
this.element.ownerDocument.defaultView.getComputedStyle(target).visibility !== "visible") {
|
|
5739
|
+
return;
|
|
5740
|
+
}
|
|
5741
|
+
const bounds = canvas.getBoundingClientRect();
|
|
5742
|
+
if (event.clientX < bounds.left || event.clientX >= bounds.right || event.clientY < bounds.top || event.clientY >= bounds.bottom) {
|
|
5743
|
+
return;
|
|
5744
|
+
}
|
|
5745
|
+
this.pendingDrag = event;
|
|
5746
|
+
const doc = this.element.ownerDocument;
|
|
5747
|
+
doc.addEventListener("pointermove", this.ContinueDrag, true);
|
|
5748
|
+
doc.addEventListener("pointerup", this.FinishPendingDrag, true);
|
|
5749
|
+
doc.addEventListener("pointercancel", this.FinishPendingDrag, true);
|
|
5750
|
+
doc.defaultView.addEventListener("blur", this.EndPendingDrag);
|
|
5751
|
+
};
|
|
5752
|
+
this.FinishPendingDrag = (event) => {
|
|
5753
|
+
var _a;
|
|
5754
|
+
if (event.pointerId === ((_a = this.pendingDrag) === null || _a === void 0 ? void 0 : _a.pointerId)) {
|
|
5755
|
+
this.EndPendingDrag();
|
|
5756
|
+
}
|
|
5757
|
+
};
|
|
5758
|
+
this.EndPendingDrag = () => {
|
|
5759
|
+
this.pendingDrag = null;
|
|
5760
|
+
const doc = this.element.ownerDocument;
|
|
5761
|
+
doc.removeEventListener("pointermove", this.ContinueDrag, true);
|
|
5762
|
+
doc.removeEventListener("pointerup", this.FinishPendingDrag, true);
|
|
5763
|
+
doc.removeEventListener("pointercancel", this.FinishPendingDrag, true);
|
|
5764
|
+
doc.defaultView.removeEventListener("blur", this.EndPendingDrag);
|
|
5765
|
+
};
|
|
5766
|
+
this.ContinueDrag = (event) => {
|
|
5767
|
+
const start = this.pendingDrag;
|
|
5768
|
+
if (!start || event.pointerId !== start.pointerId) {
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5771
|
+
if (!(event.buttons & 1) || this.viewer.isDestroyed() || !this.element.contains(start.target)) {
|
|
5772
|
+
this.EndPendingDrag();
|
|
5773
|
+
return;
|
|
5774
|
+
}
|
|
5775
|
+
// Keep ordinary clicks local; only a deliberate drag starts Cesium's camera gesture.
|
|
5776
|
+
if (Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) < 6) {
|
|
5777
|
+
return;
|
|
5778
|
+
}
|
|
5779
|
+
this.EndPendingDrag();
|
|
5780
|
+
const canvas = this.viewer.canvas;
|
|
5781
|
+
try {
|
|
5782
|
+
canvas.setPointerCapture(start.pointerId);
|
|
5783
|
+
}
|
|
5784
|
+
catch {
|
|
5785
|
+
// A cancelled pointer or unsupported capture still cannot start native image dragging.
|
|
5786
|
+
return;
|
|
5787
|
+
}
|
|
5788
|
+
const win = this.element.ownerDocument.defaultView;
|
|
5789
|
+
const copy = (source) => ({
|
|
5790
|
+
bubbles: true, cancelable: true, pointerId: source.pointerId, pointerType: source.pointerType,
|
|
5791
|
+
isPrimary: source.isPrimary, button: source.button, buttons: source.buttons,
|
|
5792
|
+
clientX: source.clientX, clientY: source.clientY, screenX: source.screenX, screenY: source.screenY,
|
|
5793
|
+
ctrlKey: source.ctrlKey, shiftKey: source.shiftKey, altKey: source.altKey, metaKey: source.metaKey
|
|
5794
|
+
});
|
|
5795
|
+
// Capture routes subsequent real move/up events to Cesium, including releases outside the label.
|
|
5796
|
+
canvas.dispatchEvent(new win.PointerEvent("pointerdown", copy(start)));
|
|
5797
|
+
canvas.dispatchEvent(new win.PointerEvent("pointermove", copy(event)));
|
|
5798
|
+
event.preventDefault();
|
|
5799
|
+
event.stopPropagation();
|
|
5800
|
+
this.viewer.scene.requestRender();
|
|
5801
|
+
};
|
|
5802
|
+
this.ForwardWheel = (event) => {
|
|
5803
|
+
var _a, _b, _c;
|
|
5804
|
+
if (this.forwardingWheel || event.defaultPrevented || this.viewer.isDestroyed()) {
|
|
5805
|
+
return;
|
|
5806
|
+
}
|
|
5807
|
+
const target = (_b = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest) === null || _b === void 0 ? void 0 : _b.call(_a, '.entity-label [role="button"]');
|
|
5808
|
+
const canvas = this.viewer.canvas;
|
|
5809
|
+
const win = this.element.ownerDocument.defaultView;
|
|
5810
|
+
if (!target || !this.element.contains(target) || win.getComputedStyle(target).visibility !== "visible") {
|
|
5811
|
+
return;
|
|
5812
|
+
}
|
|
5813
|
+
const bounds = canvas.getBoundingClientRect();
|
|
5814
|
+
if (event.clientX < bounds.left || event.clientX >= bounds.right || event.clientY < bounds.top || event.clientY >= bounds.bottom) {
|
|
5815
|
+
return;
|
|
5816
|
+
}
|
|
5817
|
+
const position = {
|
|
5818
|
+
bubbles: true, cancelable: true, clientX: event.clientX, clientY: event.clientY,
|
|
5819
|
+
screenX: event.screenX, screenY: event.screenY, buttons: event.buttons,
|
|
5820
|
+
ctrlKey: event.ctrlKey, shiftKey: event.shiftKey, altKey: event.altKey, metaKey: event.metaKey,
|
|
5821
|
+
pointerId: 1, pointerType: "mouse", isPrimary: true
|
|
5822
|
+
};
|
|
5823
|
+
this.forwardingWheel = true;
|
|
5824
|
+
try {
|
|
5825
|
+
// Cesium's wheel zoom uses its last mouse position, not the wheel event's coordinates.
|
|
5826
|
+
const detection = Cesium.FeatureDetection;
|
|
5827
|
+
// Older Cesium versions opt Firefox out even when the browser exposes PointerEvent.
|
|
5828
|
+
canvas.dispatchEvent(((_c = detection.supportsPointerEvents) === null || _c === void 0 ? void 0 : _c.call(detection)) !== false && typeof win.PointerEvent === "function" ?
|
|
5829
|
+
new win.PointerEvent("pointermove", position) : new win.MouseEvent("mousemove", position));
|
|
5830
|
+
canvas.dispatchEvent(new win.WheelEvent("wheel", {
|
|
5831
|
+
...position, deltaX: event.deltaX, deltaY: event.deltaY, deltaZ: event.deltaZ, deltaMode: event.deltaMode
|
|
5832
|
+
}));
|
|
5833
|
+
this.viewer.scene.requestRender();
|
|
5834
|
+
event.preventDefault();
|
|
5835
|
+
event.stopPropagation();
|
|
5836
|
+
}
|
|
5837
|
+
finally {
|
|
5838
|
+
this.forwardingWheel = false;
|
|
5839
|
+
}
|
|
5840
|
+
};
|
|
5841
|
+
this.element.className = "entity-label-layer";
|
|
5842
|
+
// Depth ordering belongs inside the map overlay, never in the application's UI stack.
|
|
5843
|
+
this.element.style.cssText = "position:absolute;inset:0;z-index:0;isolation:isolate;pointer-events:none;";
|
|
5844
|
+
this.Move();
|
|
5845
|
+
this.element.addEventListener("wheel", this.ForwardWheel, { passive: false });
|
|
5846
|
+
this.element.addEventListener("pointerdown", this.BeginDrag, true);
|
|
5847
|
+
this.element.addEventListener("dragstart", this.PreventNativeDrag);
|
|
5848
|
+
this.element.ownerDocument.addEventListener("pointermove", this.TrackPointer, true);
|
|
5849
|
+
this.element.ownerDocument.addEventListener("pointerout", this.PointerOut, true);
|
|
5850
|
+
this.element.ownerDocument.defaultView.addEventListener("blur", this.ClearPointer);
|
|
5851
|
+
this.remove = viewer.scene.postUpdate.addEventListener(() => this.Update());
|
|
5852
|
+
}
|
|
5853
|
+
Move() {
|
|
5854
|
+
(containers.get(this.viewer) || this.viewer.container).appendChild(this.element);
|
|
5855
|
+
this.Update();
|
|
5856
|
+
this.viewer.scene.requestRender();
|
|
5857
|
+
}
|
|
5858
|
+
MeasureCoordinates() {
|
|
5859
|
+
var _a;
|
|
5860
|
+
const canvas = this.viewer.canvas;
|
|
5861
|
+
const canvasRect = (_a = canvas.getBoundingClientRect) === null || _a === void 0 ? void 0 : _a.call(canvas);
|
|
5862
|
+
const rect = this.element.getBoundingClientRect();
|
|
5863
|
+
const scaleX = rect.width / this.element.offsetWidth || 1;
|
|
5864
|
+
const scaleY = rect.height / this.element.offsetHeight || 1;
|
|
5865
|
+
return {
|
|
5866
|
+
x: (((canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.left) || 0) - rect.left) / scaleX,
|
|
5867
|
+
y: (((canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.top) || 0) - rect.top) / scaleY,
|
|
5868
|
+
scaleX: ((canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.width) / canvas.clientWidth || 1) / scaleX,
|
|
5869
|
+
scaleY: ((canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.height) / canvas.clientHeight || 1) / scaleY
|
|
5870
|
+
};
|
|
5871
|
+
}
|
|
5872
|
+
Add(participant) {
|
|
5873
|
+
this.participants.add(participant);
|
|
5874
|
+
this.viewer.scene.requestRender();
|
|
5875
|
+
return () => {
|
|
5876
|
+
this.participants.delete(participant);
|
|
5877
|
+
if (!this.participants.size) {
|
|
5878
|
+
this.remove();
|
|
5879
|
+
this.element.removeEventListener("wheel", this.ForwardWheel);
|
|
5880
|
+
this.element.removeEventListener("pointerdown", this.BeginDrag, true);
|
|
5881
|
+
this.element.removeEventListener("dragstart", this.PreventNativeDrag);
|
|
5882
|
+
this.element.ownerDocument.removeEventListener("pointermove", this.TrackPointer, true);
|
|
5883
|
+
this.element.ownerDocument.removeEventListener("pointerout", this.PointerOut, true);
|
|
5884
|
+
this.element.ownerDocument.defaultView.removeEventListener("blur", this.ClearPointer);
|
|
5885
|
+
this.EndPendingDrag();
|
|
5886
|
+
this.element.remove();
|
|
5887
|
+
layers.delete(this.viewer);
|
|
5888
|
+
}
|
|
5889
|
+
};
|
|
5890
|
+
}
|
|
5891
|
+
Update() {
|
|
5892
|
+
var _a, _b;
|
|
5893
|
+
this.coordinates = this.MeasureCoordinates();
|
|
5894
|
+
const rect = (_b = (_a = this.viewer.canvas).getBoundingClientRect) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
5895
|
+
const pointer = this.pointerClient;
|
|
5896
|
+
this.pointer = pointer && (rect === null || rect === void 0 ? void 0 : rect.width) && (rect === null || rect === void 0 ? void 0 : rect.height) && pointer.x >= rect.left && pointer.x < rect.right && pointer.y >= rect.top && pointer.y < rect.bottom ?
|
|
5897
|
+
{
|
|
5898
|
+
x: (pointer.x - rect.left) * this.viewer.canvas.clientWidth / rect.width,
|
|
5899
|
+
y: (pointer.y - rect.top) * this.viewer.canvas.clientHeight / rect.height
|
|
5900
|
+
} : undefined;
|
|
5901
|
+
const projected = new Map();
|
|
5902
|
+
for (const participant of this.participants) {
|
|
5903
|
+
projected.set(participant, participant.project());
|
|
5904
|
+
}
|
|
5905
|
+
const placements = new Map(Layout(Array.from(projected.values()).filter(Boolean), this.placementMemory).map(item => [item.frame.id, item]));
|
|
5906
|
+
for (const [participant, frame] of projected) {
|
|
5907
|
+
participant.apply(frame ? placements.get(frame.id) : undefined);
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
let nextLabelId = 0;
|
|
5307
5912
|
class Label {
|
|
5913
|
+
get HasText() { return this.options.presentation !== "icon"; }
|
|
5914
|
+
SetHoverVisible(visible) {
|
|
5915
|
+
var _a, _b, _c;
|
|
5916
|
+
if (!this.Transient || this.Persistent) {
|
|
5917
|
+
return;
|
|
5918
|
+
}
|
|
5919
|
+
if (!visible) {
|
|
5920
|
+
this.retainedHoverPosition = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.GetLabelHoverPosition((_b = this.rego) === null || _b === void 0 ? void 0 : _b.entityId, (_c = this.rego) === null || _c === void 0 ? void 0 : _c.menuItemId);
|
|
5921
|
+
// Retiring labels must not change the ring now owned by the next hover target.
|
|
5922
|
+
if (this.ringAnimation) {
|
|
5923
|
+
this.ringAnimation = { ...this.ringAnimation };
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
if (this.hoverFade.to === Number(visible)) {
|
|
5927
|
+
return;
|
|
5928
|
+
}
|
|
5929
|
+
this.hoverFade = { from: this.HoverOpacity(), to: Number(visible), start: Date.now() };
|
|
5930
|
+
this.viewer.scene.requestRender();
|
|
5931
|
+
}
|
|
5932
|
+
HoverOpacity() {
|
|
5933
|
+
if (!this.Transient || this.Persistent) {
|
|
5934
|
+
return 1;
|
|
5935
|
+
}
|
|
5936
|
+
const progress = Math.min(1, Math.max(0, (Date.now() - this.hoverFade.start) / 120));
|
|
5937
|
+
if (progress < 1) {
|
|
5938
|
+
this.viewer.scene.requestRender();
|
|
5939
|
+
}
|
|
5940
|
+
return this.hoverFade.from + (this.hoverFade.to - this.hoverFade.from) * progress * progress * (3 - 2 * progress);
|
|
5941
|
+
}
|
|
5308
5942
|
get Rego() {
|
|
5309
5943
|
return this.rego;
|
|
5310
5944
|
}
|
|
@@ -5317,10 +5951,18 @@
|
|
|
5317
5951
|
set pos3d(val) {
|
|
5318
5952
|
this._pos3d = val;
|
|
5319
5953
|
this.prePositioned = !isNaN(val === null || val === void 0 ? void 0 : val.x);
|
|
5320
|
-
this.
|
|
5954
|
+
if (this.label && this.prePositioned)
|
|
5955
|
+
this.viewer.scene.requestRender();
|
|
5956
|
+
else
|
|
5957
|
+
this.createLabel(val);
|
|
5321
5958
|
}
|
|
5322
5959
|
constructor(params) {
|
|
5323
|
-
var _a;
|
|
5960
|
+
var _a, _b, _c, _d;
|
|
5961
|
+
this.id = `label-${++nextLabelId}`;
|
|
5962
|
+
this.Persistent = false;
|
|
5963
|
+
this.Transient = false;
|
|
5964
|
+
this.hoverFade = { from: 0, to: 1, start: Date.now() };
|
|
5965
|
+
this.cursorMotion = { amount: 0, from: 0, target: 0, start: 0, position: undefined };
|
|
5324
5966
|
// Counter to help differentiate between createLabel calls.
|
|
5325
5967
|
this.counter = 0;
|
|
5326
5968
|
// The label element itself.
|
|
@@ -5340,15 +5982,24 @@
|
|
|
5340
5982
|
this.loadTimeout = null;
|
|
5341
5983
|
this.loadedName = false;
|
|
5342
5984
|
this.line = null;
|
|
5985
|
+
this.anchor = null;
|
|
5343
5986
|
// Null = not attempted to load.
|
|
5344
5987
|
this.additionalTexts = null;
|
|
5345
5988
|
this.rego = params.rego;
|
|
5346
5989
|
this.viewer = params.viewer;
|
|
5347
5990
|
this.api = params.api;
|
|
5348
5991
|
this.visualRegister = params.visualRegister;
|
|
5349
|
-
this.
|
|
5992
|
+
this.options = params.options || {};
|
|
5993
|
+
this.groupId = params.groupId;
|
|
5994
|
+
this.Persistent = (_a = params.persistent) !== null && _a !== void 0 ? _a : Boolean(params.groupId);
|
|
5995
|
+
this.Transient = (_b = params.transient) !== null && _b !== void 0 ? _b : false;
|
|
5996
|
+
this.hoverRingState = params.hoverRingState;
|
|
5997
|
+
this.visible = params.visible;
|
|
5998
|
+
if (((_c = params.options) === null || _c === void 0 ? void 0 : _c.text) != null)
|
|
5999
|
+
this.additionalTexts = [];
|
|
6000
|
+
this.prePositioned = !isNaN((_d = params.pos3d) === null || _d === void 0 ? void 0 : _d.x);
|
|
5350
6001
|
this.createLabel(params.pos3d);
|
|
5351
|
-
if (!params.api && !BModels.ENVIRONMENT.IS_SELF_MANAGED) {
|
|
6002
|
+
if (!params.api && !BModels.ENVIRONMENT.IS_SELF_MANAGED && this.options.text == null) {
|
|
5352
6003
|
this.api = BModels.ENVIRONMENT.Api().GetBruceApi();
|
|
5353
6004
|
}
|
|
5354
6005
|
}
|
|
@@ -5398,12 +6049,24 @@
|
|
|
5398
6049
|
clearTimeout(this.loadTimeout);
|
|
5399
6050
|
this.loadTimeout = null;
|
|
5400
6051
|
}
|
|
6052
|
+
/*
|
|
6053
|
+
* Rebuilds only when configuration changes; state refreshes must not recreate DOM every frame.
|
|
6054
|
+
*/
|
|
6055
|
+
Configure(options, groupId) {
|
|
6056
|
+
if (this.groupId === groupId && JSON.stringify(this.options) === JSON.stringify(options || {})) {
|
|
6057
|
+
return;
|
|
6058
|
+
}
|
|
6059
|
+
this.options = options || {};
|
|
6060
|
+
this.groupId = groupId;
|
|
6061
|
+
this.additionalTexts = this.options.text != null ? [] : null;
|
|
6062
|
+
this.createLabel();
|
|
6063
|
+
}
|
|
5401
6064
|
/**
|
|
5402
6065
|
* Creates cesium entity for the label if one does not exist.
|
|
5403
6066
|
* @param starterPos3d optional position to create label at. Ignored for billboard labels.
|
|
5404
6067
|
*/
|
|
5405
6068
|
async createLabel(starterPos3d) {
|
|
5406
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
6069
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
5407
6070
|
this.removeLabel();
|
|
5408
6071
|
let pos3d = starterPos3d ? starterPos3d.clone() : null;
|
|
5409
6072
|
const counter = ++this.counter;
|
|
@@ -5612,7 +6275,7 @@
|
|
|
5612
6275
|
}
|
|
5613
6276
|
clearTimeout(this.loadTimeout);
|
|
5614
6277
|
this.loadTimeout = setTimeout(async () => {
|
|
5615
|
-
var _a, _b, _c, _d;
|
|
6278
|
+
var _a, _b, _c, _d, _e;
|
|
5616
6279
|
if (this.disposed || this.counter != counter) {
|
|
5617
6280
|
return;
|
|
5618
6281
|
}
|
|
@@ -5620,10 +6283,10 @@
|
|
|
5620
6283
|
if (this.additionalTexts == null) {
|
|
5621
6284
|
const additionalTexts = [];
|
|
5622
6285
|
// Rego might not have a known or default Entity Type. Eg: OSM building.
|
|
5623
|
-
if (this.rego.entityTypeId) {
|
|
6286
|
+
if (this.rego.entityTypeId || this.options.attributes) {
|
|
5624
6287
|
let entityType = null;
|
|
5625
6288
|
try {
|
|
5626
|
-
const data = await BModels.EntityType.Get({
|
|
6289
|
+
const data = this.options.attributes ? null : await BModels.EntityType.Get({
|
|
5627
6290
|
api: this.api,
|
|
5628
6291
|
entityTypeId: this.rego.entityTypeId
|
|
5629
6292
|
});
|
|
@@ -5638,14 +6301,14 @@
|
|
|
5638
6301
|
}
|
|
5639
6302
|
// Type could be deleted, however we'll just catch that to show a label instead of nothing.
|
|
5640
6303
|
// This is not unusual for Tilesets where the Type that is baked might be outdated.
|
|
5641
|
-
if (entityType) {
|
|
5642
|
-
const attributes = (
|
|
6304
|
+
if (entityType || this.options.attributes) {
|
|
6305
|
+
const attributes = (_a = this.options.attributes) !== null && _a !== void 0 ? _a : (_c = (_b = entityType.VisualSettings) === null || _b === void 0 ? void 0 : _b.label) === null || _c === void 0 ? void 0 : _c.attributes;
|
|
5643
6306
|
if (attributes) {
|
|
5644
6307
|
try {
|
|
5645
6308
|
const { entity } = await BModels.Entity.Get({
|
|
5646
6309
|
api: this.api,
|
|
5647
6310
|
entityId: this.rego.entityId,
|
|
5648
|
-
scenario: ((
|
|
6311
|
+
scenario: ((_d = this.rego.outline) === null || _d === void 0 ? void 0 : _d.length) ? (_e = this.rego.outline.find(x => !!x.Scenario)) === null || _e === void 0 ? void 0 : _e.Scenario : null,
|
|
5649
6312
|
schemaId: this.rego.schema,
|
|
5650
6313
|
migrated: true
|
|
5651
6314
|
});
|
|
@@ -5654,7 +6317,7 @@
|
|
|
5654
6317
|
entity: entity,
|
|
5655
6318
|
path: attributes[i]
|
|
5656
6319
|
});
|
|
5657
|
-
if (value) {
|
|
6320
|
+
if (value != null) {
|
|
5658
6321
|
additionalTexts.push(value);
|
|
5659
6322
|
}
|
|
5660
6323
|
}
|
|
@@ -5683,12 +6346,166 @@
|
|
|
5683
6346
|
if (this.disposed || this.counter != counter) {
|
|
5684
6347
|
return;
|
|
5685
6348
|
}
|
|
5686
|
-
const
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
6349
|
+
const presentation = this.options.presentation || "text";
|
|
6350
|
+
let clickEntityIds = [];
|
|
6351
|
+
const selectOnClick = (_j = this.options.selectOnClick) !== null && _j !== void 0 ? _j : Boolean(this.groupId);
|
|
6352
|
+
const select = (event) => {
|
|
6353
|
+
event.preventDefault();
|
|
6354
|
+
event.stopPropagation();
|
|
6355
|
+
if (!selectOnClick || this.disposed || this.counter !== counter || !clickEntityIds.length || !this.visualRegister) {
|
|
6356
|
+
return;
|
|
6357
|
+
}
|
|
6358
|
+
this.visualRegister.ClearSelected({ requestRender: false });
|
|
6359
|
+
this.visualRegister.SetSelected({ entityIds: clickEntityIds, selected: true });
|
|
6360
|
+
};
|
|
6361
|
+
const makeClickable = (target) => {
|
|
6362
|
+
if (!selectOnClick || !this.visualRegister) {
|
|
6363
|
+
return;
|
|
6364
|
+
}
|
|
6365
|
+
target.style.pointerEvents = "auto";
|
|
6366
|
+
target.style.cursor = "pointer";
|
|
6367
|
+
target.style.userSelect = "none";
|
|
6368
|
+
target.setAttribute("role", "button");
|
|
6369
|
+
target.tabIndex = 0;
|
|
6370
|
+
target.addEventListener("click", select);
|
|
6371
|
+
target.addEventListener("keydown", event => {
|
|
6372
|
+
if (event.key === "Enter" || event.key === " ")
|
|
6373
|
+
select(event);
|
|
6374
|
+
});
|
|
6375
|
+
// Prevent viewer picking and camera gestures from interpreting label interactions.
|
|
6376
|
+
for (const type of ["pointerdown", "pointerup", "mousedown", "mouseup", "dblclick"]) {
|
|
6377
|
+
target.addEventListener(type, event => event.stopPropagation());
|
|
6378
|
+
}
|
|
6379
|
+
};
|
|
6380
|
+
const normalLeader = (_k = this.options.leader) !== null && _k !== void 0 ? _k : presentation === "text";
|
|
6381
|
+
let leader = normalLeader;
|
|
6382
|
+
const content = document.createElement("span");
|
|
6383
|
+
const originalText = (_l = this.options.text) !== null && _l !== void 0 ? _l : [text, ...additionalTexts].join("\n");
|
|
6384
|
+
let textElement;
|
|
6385
|
+
let sourceText;
|
|
6386
|
+
let sourceNaturalText;
|
|
6387
|
+
let iconElement;
|
|
6388
|
+
let iconContainer;
|
|
6389
|
+
content.className = "entity-label-content";
|
|
6390
|
+
content.style.cssText = "display:flex;align-items:center;gap:6px;";
|
|
6391
|
+
if (presentation === "icon-text-above") {
|
|
6392
|
+
content.style.flexDirection = "column-reverse";
|
|
6393
|
+
}
|
|
6394
|
+
if (presentation !== "text") {
|
|
6395
|
+
const icon = document.createElement("span");
|
|
6396
|
+
iconElement = icon;
|
|
6397
|
+
icon.className = "entity-label-icon";
|
|
6398
|
+
icon.style.cssText = `font-size:${(this.options.iconSize || 24) * ((_m = this.options.iconScale) !== null && _m !== void 0 ? _m : 1)}px;line-height:1;`;
|
|
6399
|
+
icon.style.textShadow = "0 1px 2px rgba(0, 0, 0, 0.25)";
|
|
6400
|
+
const iconColor = typeof this.options.iconColor === "string" ? this.options.iconColor : undefined;
|
|
6401
|
+
const iconBackground = this.options.iconBackground && this.options.iconScale !== 0;
|
|
6402
|
+
if (iconColor) {
|
|
6403
|
+
icon.style.color = iconColor;
|
|
6404
|
+
}
|
|
6405
|
+
if (this.options.iconUrl) {
|
|
6406
|
+
const image = document.createElement("img");
|
|
6407
|
+
image.draggable = false;
|
|
6408
|
+
image.alt = this.options.icon || "";
|
|
6409
|
+
const scale = (_o = this.options.iconScale) !== null && _o !== void 0 ? _o : 1;
|
|
6410
|
+
const size = this.options.iconSize;
|
|
6411
|
+
const mask = iconColor && iconBackground ? document.createElement("span") : icon;
|
|
6412
|
+
if (mask !== icon) {
|
|
6413
|
+
icon.appendChild(mask);
|
|
6414
|
+
}
|
|
6415
|
+
const target = iconColor ? mask : image;
|
|
6416
|
+
if (iconColor) {
|
|
6417
|
+
mask.style.display = "inline-block";
|
|
6418
|
+
mask.style.backgroundColor = iconColor;
|
|
6419
|
+
for (const prefix of ["", "-webkit-"]) {
|
|
6420
|
+
mask.style.setProperty(`${prefix}mask-image`, `url(${JSON.stringify(this.options.iconUrl)})`);
|
|
6421
|
+
mask.style.setProperty(`${prefix}mask-size`, "contain");
|
|
6422
|
+
mask.style.setProperty(`${prefix}mask-repeat`, "no-repeat");
|
|
6423
|
+
mask.style.setProperty(`${prefix}mask-position`, "center");
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
const resize = () => {
|
|
6427
|
+
if (this.disposed || this.counter !== counter) {
|
|
6428
|
+
return;
|
|
6429
|
+
}
|
|
6430
|
+
const intrinsic = this.options.iconScale != null && size == null;
|
|
6431
|
+
target.style.width = `${(intrinsic ? image.naturalWidth || 24 : size || 24) * scale}px`;
|
|
6432
|
+
target.style.height = `${(intrinsic ? image.naturalHeight || 24 : size || 24) * scale}px`;
|
|
6433
|
+
this.viewer.scene.requestRender();
|
|
6434
|
+
};
|
|
6435
|
+
image.onload = resize;
|
|
6436
|
+
resize();
|
|
6437
|
+
image.src = this.options.iconUrl;
|
|
6438
|
+
if (!iconColor) {
|
|
6439
|
+
icon.appendChild(image);
|
|
6440
|
+
}
|
|
6441
|
+
}
|
|
6442
|
+
else if (typeof this.options.iconClass === "string" && this.options.iconClass) {
|
|
6443
|
+
icon.className = `entity-label-icon ${this.options.iconClass}`;
|
|
6444
|
+
}
|
|
6445
|
+
else {
|
|
6446
|
+
icon.textContent = this.options.icon || "โ";
|
|
6447
|
+
}
|
|
6448
|
+
if (iconBackground) {
|
|
6449
|
+
const color = Cesium.Color.fromCssColorString(iconColor || "white") || Cesium.Color.WHITE;
|
|
6450
|
+
const luminance = 0.2126 * color.red + 0.7152 * color.green + 0.0722 * color.blue;
|
|
6451
|
+
const background = (luminance > 0.5 ? color.darken(ICON_BACKGROUND_BLEND, new Cesium.Color()) :
|
|
6452
|
+
color.brighten(ICON_BACKGROUND_BLEND, new Cesium.Color()));
|
|
6453
|
+
const size = (this.options.iconSize || 24) * ((_p = this.options.iconScale) !== null && _p !== void 0 ? _p : 1);
|
|
6454
|
+
icon.style.backgroundColor = background.withAlpha(ICON_BACKGROUND_ALPHA).toCssColorString();
|
|
6455
|
+
icon.style.borderRadius = "50%";
|
|
6456
|
+
icon.style.padding = `${size / 3}px`;
|
|
6457
|
+
icon.style.display = "inline-flex";
|
|
6458
|
+
icon.style.alignItems = "center";
|
|
6459
|
+
icon.style.justifyContent = "center";
|
|
6460
|
+
icon.style.minWidth = `${size}px`;
|
|
6461
|
+
icon.style.minHeight = `${size}px`;
|
|
6462
|
+
icon.style.boxSizing = "content-box";
|
|
6463
|
+
}
|
|
6464
|
+
if (this.options.iconScale === 0) {
|
|
6465
|
+
icon.style.display = "none";
|
|
6466
|
+
}
|
|
6467
|
+
makeClickable(icon);
|
|
6468
|
+
// Keep badges outside the glyph so font classes and image masks cannot affect them.
|
|
6469
|
+
iconContainer = document.createElement("span");
|
|
6470
|
+
iconContainer.style.cssText = "position:relative;display:inline-flex;flex:none;";
|
|
6471
|
+
iconContainer.appendChild(icon);
|
|
6472
|
+
content.appendChild(iconContainer);
|
|
6473
|
+
}
|
|
6474
|
+
if (presentation !== "icon") {
|
|
6475
|
+
textElement = document.createElement("span");
|
|
6476
|
+
textElement.className = "entity-label-text";
|
|
6477
|
+
const textStyle = `white-space:pre-wrap;overflow-wrap:anywhere;max-width:${TEXT_MAX_WIDTH}px;width:max-content;flex-shrink:0;`;
|
|
6478
|
+
textElement.style.cssText = textStyle;
|
|
6479
|
+
textElement.textContent = originalText;
|
|
6480
|
+
if (presentation === "text")
|
|
6481
|
+
makeClickable(textElement);
|
|
6482
|
+
content.appendChild(textElement);
|
|
6483
|
+
if ((_q = this.options.cluster) === null || _q === void 0 ? void 0 : _q.enabled) {
|
|
6484
|
+
sourceText = document.createElement("span");
|
|
6485
|
+
sourceText.className = "entity-label-source-text";
|
|
6486
|
+
sourceText.setAttribute("aria-hidden", "true");
|
|
6487
|
+
sourceText.style.cssText = textStyle + "position:absolute;visibility:hidden;pointer-events:none;";
|
|
6488
|
+
sourceText.textContent = originalText;
|
|
6489
|
+
content.appendChild(sourceText);
|
|
6490
|
+
// Measure the original unwrapped text, never a rendered cluster summary.
|
|
6491
|
+
sourceNaturalText = document.createElement("span");
|
|
6492
|
+
sourceNaturalText.setAttribute("aria-hidden", "true");
|
|
6493
|
+
sourceNaturalText.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;white-space:pre;width:max-content;";
|
|
6494
|
+
sourceNaturalText.textContent = originalText;
|
|
6495
|
+
content.appendChild(sourceNaturalText);
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6498
|
+
const countElement = document.createElement("span");
|
|
6499
|
+
countElement.className = "entity-label-count";
|
|
6500
|
+
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;";
|
|
6501
|
+
if (iconContainer) {
|
|
6502
|
+
countElement.style.cssText += "position:absolute;left:100%;top:0;transform:translate(-50%,-50%);";
|
|
6503
|
+
iconContainer.appendChild(countElement);
|
|
6504
|
+
}
|
|
6505
|
+
if (!layers.has(this.viewer)) {
|
|
6506
|
+
layers.set(this.viewer, new Layer(this.viewer));
|
|
6507
|
+
}
|
|
6508
|
+
const layer = layers.get(this.viewer);
|
|
5692
6509
|
let ele = null;
|
|
5693
6510
|
let lineEle = null;
|
|
5694
6511
|
if (this.label) {
|
|
@@ -5696,11 +6513,22 @@
|
|
|
5696
6513
|
}
|
|
5697
6514
|
else {
|
|
5698
6515
|
ele = document.createElement("div");
|
|
5699
|
-
ele.
|
|
6516
|
+
ele.appendChild(content);
|
|
6517
|
+
if (!iconContainer) {
|
|
6518
|
+
ele.appendChild(countElement);
|
|
6519
|
+
}
|
|
6520
|
+
ele.className = "entity-label";
|
|
6521
|
+
ele.dataset.entityId = ((_r = this.rego) === null || _r === void 0 ? void 0 : _r.entityId) || "";
|
|
6522
|
+
ele.dataset.presentation = presentation;
|
|
6523
|
+
if (this.groupId) {
|
|
6524
|
+
ele.dataset.groupId = this.groupId;
|
|
6525
|
+
}
|
|
5700
6526
|
ele.setAttribute("style", `
|
|
5701
6527
|
position: absolute;
|
|
5702
6528
|
z-index: 0;
|
|
5703
6529
|
display: none;
|
|
6530
|
+
align-items: center;
|
|
6531
|
+
gap: 6px;
|
|
5704
6532
|
pointer-events: none;
|
|
5705
6533
|
padding: 6px 8px;
|
|
5706
6534
|
border-radius: 6px;
|
|
@@ -5709,9 +6537,10 @@
|
|
|
5709
6537
|
border-radius: 9px;
|
|
5710
6538
|
color: #ffffff;
|
|
5711
6539
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
|
|
5712
|
-
|
|
6540
|
+
`);
|
|
5713
6541
|
this.label = ele;
|
|
5714
|
-
|
|
6542
|
+
ele.style.width = "max-content";
|
|
6543
|
+
layer.element.appendChild(ele);
|
|
5715
6544
|
}
|
|
5716
6545
|
if (this.line) {
|
|
5717
6546
|
lineEle = this.line;
|
|
@@ -5728,7 +6557,10 @@
|
|
|
5728
6557
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
|
5729
6558
|
`);
|
|
5730
6559
|
this.line = lineEle;
|
|
5731
|
-
|
|
6560
|
+
lineEle.className = "entity-label-leader";
|
|
6561
|
+
if (this.options.leaderColor)
|
|
6562
|
+
lineEle.style.background = this.options.leaderColor;
|
|
6563
|
+
// A separate anchor keeps the stem out of the hollow centre when proximity opens the ring.
|
|
5732
6564
|
const lineEleNode = document.createElement("div");
|
|
5733
6565
|
lineEleNode.setAttribute("style", `
|
|
5734
6566
|
position: absolute;
|
|
@@ -5741,35 +6573,20 @@
|
|
|
5741
6573
|
top: -2px;
|
|
5742
6574
|
left: -2px;
|
|
5743
6575
|
`);
|
|
5744
|
-
|
|
5745
|
-
|
|
6576
|
+
lineEleNode.className = "entity-label-anchor";
|
|
6577
|
+
// SVG preserves fractional strokes in scaled containers where CSS borders round to pixels.
|
|
6578
|
+
const ringSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
6579
|
+
ringSvg.style.cssText = "position:absolute;inset:0;width:100%;height:100%;overflow:visible;";
|
|
6580
|
+
ringSvg.setAttribute("aria-hidden", "true");
|
|
6581
|
+
ringSvg.setAttribute("preserveAspectRatio", "none");
|
|
6582
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
6583
|
+
circle.setAttribute("fill", "none");
|
|
6584
|
+
ringSvg.appendChild(circle);
|
|
6585
|
+
lineEleNode.appendChild(ringSvg);
|
|
6586
|
+
this.anchor = lineEleNode;
|
|
6587
|
+
layer.element.appendChild(lineEleNode);
|
|
6588
|
+
layer.element.appendChild(lineEle);
|
|
5746
6589
|
}
|
|
5747
|
-
let _lastDistance = null;
|
|
5748
|
-
let _lastCameraPos = null;
|
|
5749
|
-
const getDistance = () => {
|
|
5750
|
-
var _a;
|
|
5751
|
-
if (this.disposed) {
|
|
5752
|
-
return null;
|
|
5753
|
-
}
|
|
5754
|
-
const cameraPos = (_a = this.viewer.camera) === null || _a === void 0 ? void 0 : _a.position;
|
|
5755
|
-
if (isNaN(cameraPos === null || cameraPos === void 0 ? void 0 : cameraPos.x)) {
|
|
5756
|
-
return null;
|
|
5757
|
-
}
|
|
5758
|
-
// If camera hasn't moved much then we can use the last distance.
|
|
5759
|
-
const TOLERANCE = 0.1;
|
|
5760
|
-
if (_lastCameraPos) {
|
|
5761
|
-
const totalMovement = Math.abs(_lastCameraPos.x - cameraPos.x) +
|
|
5762
|
-
Math.abs(_lastCameraPos.y - cameraPos.y) +
|
|
5763
|
-
Math.abs(_lastCameraPos.z - cameraPos.z);
|
|
5764
|
-
if (totalMovement < TOLERANCE) {
|
|
5765
|
-
return _lastDistance;
|
|
5766
|
-
}
|
|
5767
|
-
}
|
|
5768
|
-
const distance = Cesium.Cartesian3.distance(cameraPos, this._pos3d);
|
|
5769
|
-
_lastDistance = distance;
|
|
5770
|
-
_lastCameraPos = cameraPos.clone();
|
|
5771
|
-
return distance;
|
|
5772
|
-
};
|
|
5773
6590
|
let MAX_DISTANCE = Math.max(15000, sizeInM * 35);
|
|
5774
6591
|
if (visual && visual instanceof Cesium.Entity) {
|
|
5775
6592
|
// Consistent sized things.
|
|
@@ -5777,123 +6594,399 @@
|
|
|
5777
6594
|
MAX_DISTANCE = Infinity;
|
|
5778
6595
|
}
|
|
5779
6596
|
}
|
|
5780
|
-
const
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
6597
|
+
const fitLeader = (anchorX, anchorY, desired, width, height, radius = 0) => {
|
|
6598
|
+
const above = Math.max(0, anchorY - height);
|
|
6599
|
+
const below = Math.max(0, this.viewer.canvas.clientHeight - anchorY - height);
|
|
6600
|
+
// Keep a short visible stem before switching sides; never aim it at the cursor or a box corner.
|
|
6601
|
+
const upwards = above >= Math.max(radius ? radius + 4 : 0, Math.min(8, desired)) || above >= below;
|
|
6602
|
+
const length = Math.min(desired, upwards ? above : below);
|
|
6603
|
+
const endY = anchorY + (upwards ? -length : length);
|
|
6604
|
+
return {
|
|
6605
|
+
x: Math.max(0, Math.min(anchorX, this.viewer.canvas.clientWidth - width)),
|
|
6606
|
+
y: upwards ? endY - height : endY, endY
|
|
6607
|
+
};
|
|
6608
|
+
};
|
|
6609
|
+
let cursorMotion = this.cursorMotion;
|
|
6610
|
+
const project = () => {
|
|
6611
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
6612
|
+
if (this.disposed || !this.viewer || this.viewer.isDestroyed() || ((_a = this.visible) === null || _a === void 0 ? void 0 : _a.call(this)) === false ||
|
|
6613
|
+
(presentation === "icon" && this.options.iconScale === 0)) {
|
|
6614
|
+
return null;
|
|
5784
6615
|
}
|
|
5785
|
-
if (!this.
|
|
5786
|
-
this.
|
|
5787
|
-
return;
|
|
6616
|
+
if (this.Transient && !this.Persistent && this.hoverFade.to === 0 &&
|
|
6617
|
+
(this.hoverFade.from === 0 || Date.now() - this.hoverFade.start >= 120)) {
|
|
6618
|
+
return null;
|
|
5788
6619
|
}
|
|
5789
|
-
|
|
5790
|
-
if (
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
6620
|
+
// Moving point/model positions must be sampled at the current clock time.
|
|
6621
|
+
if (!this.prePositioned && visual instanceof Cesium.Entity && visual.position) {
|
|
6622
|
+
const position = getValue(this.viewer, visual.position);
|
|
6623
|
+
if (position)
|
|
6624
|
+
this._pos3d = exports.DrawingUtils.EnsurePosHeight({
|
|
6625
|
+
desiredHeightRef: Cesium.HeightReference.NONE, heightRef, pos3d: position, viewer: this.viewer
|
|
6626
|
+
});
|
|
5794
6627
|
}
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
6628
|
+
if (!Number.isFinite((_b = this._pos3d) === null || _b === void 0 ? void 0 : _b.x)) {
|
|
6629
|
+
return null;
|
|
6630
|
+
}
|
|
6631
|
+
const camera = this.viewer.camera;
|
|
6632
|
+
const cameraPosition = camera.positionWC || camera.position;
|
|
6633
|
+
const relative = Cesium.Cartesian3.subtract(this._pos3d, cameraPosition, new Cesium.Cartesian3());
|
|
6634
|
+
const depth = Cesium.Cartesian3.dot(relative, camera.directionWC || camera.direction);
|
|
6635
|
+
const distance = Cesium.Cartesian3.magnitude(relative);
|
|
6636
|
+
if (!Number.isFinite(distance) || depth <= 0 || distance < ((_c = this.options.near) !== null && _c !== void 0 ? _c : 0) ||
|
|
6637
|
+
distance > ((_d = this.options.far) !== null && _d !== void 0 ? _d : Infinity) || (!this.prePositioned && distance >= MAX_DISTANCE)) {
|
|
6638
|
+
return null;
|
|
6639
|
+
}
|
|
6640
|
+
const transforms = Cesium.SceneTransforms;
|
|
6641
|
+
const projectPosition = transforms.wgs84ToWindowCoordinates || transforms.worldToWindowCoordinates;
|
|
6642
|
+
const anchor = projectPosition(this.viewer.scene, this._pos3d);
|
|
6643
|
+
if (!Number.isFinite(anchor === null || anchor === void 0 ? void 0 : anchor.x) || !Number.isFinite(anchor === null || anchor === void 0 ? void 0 : anchor.y)) {
|
|
6644
|
+
return null;
|
|
6645
|
+
}
|
|
6646
|
+
if (leader && (anchor.x < 0 || anchor.y < 0 || anchor.x >= this.viewer.canvas.clientWidth || anchor.y >= this.viewer.canvas.clientHeight))
|
|
6647
|
+
return null;
|
|
6648
|
+
const transientPivot = (this.Transient && !this.Persistent ?
|
|
6649
|
+
(this.hoverFade.to === 0 ? this.retainedHoverPosition : (_e = this.visualRegister) === null || _e === void 0 ? void 0 : _e.GetLabelHoverPosition((_f = this.rego) === null || _f === void 0 ? void 0 : _f.entityId, (_g = this.rego) === null || _g === void 0 ? void 0 : _g.menuItemId)) : undefined);
|
|
6650
|
+
const hover = (presentation !== "icon" ?
|
|
6651
|
+
(this.Transient && !this.Persistent && this.hoverFade.to === 0 ? this.retainedHoverPosition :
|
|
6652
|
+
(_h = this.visualRegister) === null || _h === void 0 ? void 0 : _h.GetLabelHoverPosition((_j = this.rego) === null || _j === void 0 ? void 0 : _j.entityId, (_k = this.rego) === null || _k === void 0 ? void 0 : _k.menuItemId)) : undefined);
|
|
6653
|
+
const reused = !this.Transient || this.Persistent;
|
|
6654
|
+
const now = Date.now();
|
|
6655
|
+
const animateCursor = () => {
|
|
6656
|
+
const progress = Math.min(1, Math.max(0, (now - cursorMotion.start) / 200));
|
|
6657
|
+
const eased = progress * progress * (3 - 2 * progress);
|
|
6658
|
+
cursorMotion.amount = cursorMotion.from + (cursorMotion.target - cursorMotion.from) * eased;
|
|
6659
|
+
return progress;
|
|
6660
|
+
};
|
|
6661
|
+
animateCursor();
|
|
6662
|
+
const cursorTarget = reused && hover ? 1 : 0;
|
|
6663
|
+
if (cursorMotion.target !== cursorTarget) {
|
|
6664
|
+
cursorMotion = { ...cursorMotion, from: cursorMotion.amount, target: cursorTarget, start: now };
|
|
6665
|
+
}
|
|
6666
|
+
if (hover) {
|
|
6667
|
+
cursorMotion.position = { x: hover.x, y: hover.y };
|
|
6668
|
+
}
|
|
6669
|
+
if (animateCursor() < 1 && cursorMotion.from !== cursorMotion.target) {
|
|
6670
|
+
this.viewer.scene.requestRender();
|
|
5804
6671
|
}
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
6672
|
+
this.cursorMotion = cursorMotion;
|
|
6673
|
+
const cursorAmount = cursorMotion.amount;
|
|
6674
|
+
leader = normalLeader || cursorAmount > 0;
|
|
6675
|
+
let x = ((_l = transientPivot === null || transientPivot === void 0 ? void 0 : transientPivot.x) !== null && _l !== void 0 ? _l : anchor.x) + pixelOffset.x;
|
|
6676
|
+
let y = ((_m = transientPivot === null || transientPivot === void 0 ? void 0 : transientPivot.y) !== null && _m !== void 0 ? _m : anchor.y) + pixelOffset.y;
|
|
6677
|
+
if (cursorAmount > 0) {
|
|
6678
|
+
// A leader-less label starts centred on its anchor; preserve that box as it lifts away.
|
|
6679
|
+
if (!normalLeader) {
|
|
6680
|
+
x -= ele.offsetWidth / layer.coordinates.scaleX / 2;
|
|
6681
|
+
y += ele.offsetHeight / layer.coordinates.scaleY / 2;
|
|
6682
|
+
}
|
|
6683
|
+
x += (cursorMotion.position.x + pixelOffset.x - x) * cursorAmount;
|
|
6684
|
+
y += (cursorMotion.position.y + pixelOffset.y - y) * cursorAmount;
|
|
6685
|
+
}
|
|
6686
|
+
const anchorX = x;
|
|
6687
|
+
const anchorY = y;
|
|
6688
|
+
let leaderLength;
|
|
6689
|
+
if (leader) {
|
|
6690
|
+
if (!normalLeader) {
|
|
6691
|
+
leaderLength = 0;
|
|
6692
|
+
}
|
|
6693
|
+
else if (this.options.leaderLength != null) {
|
|
6694
|
+
leaderLength = Math.max(0, this.options.leaderLength);
|
|
6695
|
+
}
|
|
6696
|
+
else if (transientPivot) {
|
|
6697
|
+
// Cursor callouts must not jump when the next hover target has a different extent.
|
|
6698
|
+
leaderLength = 96;
|
|
5824
6699
|
}
|
|
5825
6700
|
else {
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
//
|
|
5832
|
-
|
|
5833
|
-
//
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
const
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
6701
|
+
const point = Cesium.Cartographic.fromCartesian(this._pos3d);
|
|
6702
|
+
const height = (this.prePositioned ? distance / 24 : sizeInM > 0 ?
|
|
6703
|
+
Math.min(distance / 5, sizeInM * 1.2) : Math.min(distance, camera.positionCartographic.height) / 7);
|
|
6704
|
+
point.height += Math.max(0.001, height);
|
|
6705
|
+
const end = projectPosition(this.viewer.scene, Cesium.Cartographic.toCartesian(point));
|
|
6706
|
+
// A tall world-space leader can cross the camera plane while its anchor remains visible.
|
|
6707
|
+
leaderLength = Number.isFinite(end === null || end === void 0 ? void 0 : end.x) && Number.isFinite(end === null || end === void 0 ? void 0 : end.y) ? Math.hypot(end.x - anchor.x, end.y - anchor.y) : 24;
|
|
6708
|
+
// Scale after projection so large areas and routes get shorter leaders at every zoom.
|
|
6709
|
+
if (visual instanceof Cesium.Entity && (visual.polygon || visual.polyline))
|
|
6710
|
+
leaderLength /= 3;
|
|
6711
|
+
}
|
|
6712
|
+
if (cursorAmount > 0) {
|
|
6713
|
+
leaderLength += (96 - leaderLength) * cursorAmount;
|
|
6714
|
+
}
|
|
6715
|
+
y = anchorY - leaderLength;
|
|
6716
|
+
}
|
|
6717
|
+
else if (hover && !reused) {
|
|
6718
|
+
x = hover.x + pixelOffset.x;
|
|
6719
|
+
y = hover.y + pixelOffset.y - 24;
|
|
6720
|
+
}
|
|
6721
|
+
// Hidden participants remain measurable; visibility never removes their layout boxes.
|
|
6722
|
+
const coordinates = layer.coordinates;
|
|
6723
|
+
const width = ele.offsetWidth / coordinates.scaleX;
|
|
6724
|
+
const height = ele.offsetHeight / coordinates.scaleY;
|
|
6725
|
+
let clusterBounds;
|
|
6726
|
+
if ((_o = this.options.cluster) === null || _o === void 0 ? void 0 : _o.enabled) {
|
|
6727
|
+
const textWidth = (sourceText === null || sourceText === void 0 ? void 0 : sourceText.offsetWidth) || 0;
|
|
6728
|
+
const textHeight = (sourceText === null || sourceText === void 0 ? void 0 : sourceText.offsetHeight) || 0;
|
|
6729
|
+
const iconWidth = (iconElement === null || iconElement === void 0 ? void 0 : iconElement.offsetWidth) || 0;
|
|
6730
|
+
const iconHeight = (iconElement === null || iconElement === void 0 ? void 0 : iconElement.offsetHeight) || 0;
|
|
6731
|
+
const gap = sourceText && iconWidth ? 6 : 0;
|
|
6732
|
+
const above = presentation === "icon-text-above";
|
|
6733
|
+
// Match the fixed content gap and label padding, excluding the count badge.
|
|
6734
|
+
const baseWidth = ((above ? Math.max(textWidth, iconWidth) : textWidth + iconWidth + gap) + 16) / coordinates.scaleX;
|
|
6735
|
+
const baseHeight = ((above ? textHeight + iconHeight + gap : Math.max(textHeight, iconHeight)) + 12) / coordinates.scaleY;
|
|
6736
|
+
clusterBounds = {
|
|
6737
|
+
x: leader ? x : x - baseWidth / 2,
|
|
6738
|
+
y: leader ? y - baseHeight : y - baseHeight / 2, width: baseWidth, height: baseHeight
|
|
6739
|
+
};
|
|
6740
|
+
}
|
|
6741
|
+
if (!leader) {
|
|
6742
|
+
x -= width / 2;
|
|
6743
|
+
y -= height / 2;
|
|
6744
|
+
}
|
|
6745
|
+
// Membership uses the unclamped source footprint, never the summary's changing dimensions.
|
|
6746
|
+
if (leader)
|
|
6747
|
+
({ x, y } = fitLeader(anchorX, anchorY, leaderLength, width, height));
|
|
6748
|
+
const bounds = clusterBounds || { x, y, width, height };
|
|
6749
|
+
if (!leader && (bounds.x + bounds.width < 0 || bounds.y + bounds.height < 0 || bounds.x > this.viewer.canvas.clientWidth || bounds.y > this.viewer.canvas.clientHeight)) {
|
|
6750
|
+
return null;
|
|
6751
|
+
}
|
|
6752
|
+
const state = (_p = this.visualRegister) === null || _p === void 0 ? void 0 : _p.GetState({ entityId: (_q = this.rego) === null || _q === void 0 ? void 0 : _q.entityId, menuItemId: (_r = this.rego) === null || _r === void 0 ? void 0 : _r.menuItemId });
|
|
6753
|
+
const opacity = this.prePositioned || MAX_DISTANCE === Infinity ? 1 : 1 - distance / MAX_DISTANCE;
|
|
6754
|
+
return {
|
|
6755
|
+
canFlip: leader && presentation !== "icon", hasLeader: leader,
|
|
6756
|
+
textWrapped: ((sourceNaturalText === null || sourceNaturalText === void 0 ? void 0 : sourceNaturalText.offsetWidth) || 0) > TEXT_MAX_WIDTH,
|
|
6757
|
+
transient: this.Transient || Boolean(hover) || cursorAmount > 0,
|
|
6758
|
+
extendedGeometry: visual instanceof Cesium.Entity && Boolean(visual.polygon || visual.polyline || visual.corridor),
|
|
6759
|
+
viewportWidth: this.viewer.canvas.clientWidth,
|
|
6760
|
+
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,
|
|
6761
|
+
entityId: (_t = this.rego) === null || _t === void 0 ? void 0 : _t.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, distance,
|
|
6762
|
+
// Priority shows the hovered member individually without dragging its cluster along.
|
|
6763
|
+
opacity, priority: hover || cursorAmount > 0 || (state === null || state === void 0 ? void 0 : state.highlighted) ? 1 : 0, options: this.options, text: originalText, clusterBounds
|
|
6764
|
+
};
|
|
6765
|
+
};
|
|
6766
|
+
let displacement = { x: 0, y: 0 };
|
|
6767
|
+
let displayedSummaryMore = false;
|
|
6768
|
+
let nudge = { x: 0, y: 0, fromX: 0, fromY: 0, targetX: 0, targetY: 0, start: 0 };
|
|
6769
|
+
const apply = (placement) => {
|
|
6770
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
6771
|
+
const show = (placement === null || placement === void 0 ? void 0 : placement.visible) && placement.opacity > 0;
|
|
6772
|
+
clickEntityIds = show ? placement.entityIds : [];
|
|
6773
|
+
ele.style.visibility = show ? "visible" : "hidden";
|
|
6774
|
+
lineEle.style.display = show && leader ? "block" : "none";
|
|
6775
|
+
this.anchor.style.display = show && leader ? "block" : "none";
|
|
6776
|
+
if (!show) {
|
|
6777
|
+
displacement = { x: 0, y: 0 };
|
|
6778
|
+
nudge = { x: 0, y: 0, fromX: 0, fromY: 0, targetX: 0, targetY: 0, start: 0 };
|
|
6779
|
+
if (!this.Transient) {
|
|
6780
|
+
this.ringAnimation = undefined;
|
|
5860
6781
|
}
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
6782
|
+
return;
|
|
6783
|
+
}
|
|
6784
|
+
const displayText = (_a = placement.text) !== null && _a !== void 0 ? _a : originalText;
|
|
6785
|
+
const summaryMore = Boolean(placement.summaryMore);
|
|
6786
|
+
if (textElement && (textElement.textContent !== displayText + (summaryMore ? "\nโฆ" : "") || displayedSummaryMore !== summaryMore)) {
|
|
6787
|
+
textElement.textContent = displayText;
|
|
6788
|
+
if (summaryMore) {
|
|
6789
|
+
const more = document.createElement("span");
|
|
6790
|
+
more.className = "entity-label-more";
|
|
6791
|
+
more.style.opacity = "0.65";
|
|
6792
|
+
more.textContent = "\nโฆ";
|
|
6793
|
+
textElement.appendChild(more);
|
|
6794
|
+
}
|
|
6795
|
+
displayedSummaryMore = summaryMore;
|
|
6796
|
+
// Measure the summary's footprint next frame without replacing each member's source text.
|
|
6797
|
+
this.viewer.scene.requestRender();
|
|
6798
|
+
}
|
|
6799
|
+
const frame = placement.frame;
|
|
6800
|
+
const coordinates = layer.coordinates;
|
|
6801
|
+
const opacity = placement.opacity * this.HoverOpacity();
|
|
6802
|
+
ele.style.opacity = String(opacity);
|
|
6803
|
+
ele.style.zIndex = String(placement.zIndex);
|
|
6804
|
+
ele.dataset.clusterCount = String(placement.members.length || 1);
|
|
6805
|
+
countElement.style.display = placement.members.length ? "block" : "none";
|
|
6806
|
+
countElement.style.order = placement.textSide === "left" ? "-1" : "0";
|
|
6807
|
+
const count = placement.members.length ? String(placement.members.length) : "";
|
|
6808
|
+
if (countElement.textContent !== count) {
|
|
6809
|
+
countElement.textContent = count;
|
|
6810
|
+
// The badge participates in layout, so its new width needs another measurement.
|
|
6811
|
+
this.viewer.scene.requestRender();
|
|
6812
|
+
}
|
|
6813
|
+
if (iconContainer) {
|
|
6814
|
+
const badgeWidth = countElement.offsetWidth;
|
|
6815
|
+
const iconWidth = iconElement.offsetWidth;
|
|
6816
|
+
const narrow = iconWidth < iconElement.offsetHeight * 0.6;
|
|
6817
|
+
const clearance = badgeWidth ? (narrow ? badgeWidth / 2 + 2 : Math.max(0, badgeWidth / 2 - iconWidth / 4)) : 0;
|
|
6818
|
+
countElement.style.left = `calc(100% + ${clearance}px)`;
|
|
6819
|
+
// Reserve the badge overhang so adjacent text and viewport edges remain clear.
|
|
6820
|
+
iconContainer.style.marginTop = `${countElement.offsetHeight / 2}px`;
|
|
6821
|
+
iconContainer.style.marginRight = `${badgeWidth / 2 + clearance}px`;
|
|
6822
|
+
}
|
|
6823
|
+
// Summary and badge changes must fit on their first visible frame, including after resize.
|
|
6824
|
+
const ring = this.options.anchorRing;
|
|
6825
|
+
const pointer = (layer.pointer || (cursorMotion.target ? cursorMotion.position : undefined) || (this.Transient && !this.Persistent ?
|
|
6826
|
+
(this.hoverFade.to === 0 ? this.retainedHoverPosition : (_b = this.visualRegister) === null || _b === void 0 ? void 0 : _b.GetLabelHoverPosition((_c = this.rego) === null || _c === void 0 ? void 0 : _c.entityId, (_d = this.rego) === null || _d === void 0 ? void 0 : _d.menuItemId)) : undefined));
|
|
6827
|
+
const hovered = pointer && Math.hypot(pointer.x - frame.anchorX, pointer.y - frame.anchorY) <= ((_e = ring === null || ring === void 0 ? void 0 : ring.hoverDistance) !== null && _e !== void 0 ? _e : 24);
|
|
6828
|
+
const normalRadius = (!leader || (ring === null || ring === void 0 ? void 0 : ring.enabled) === false ? 0 : Math.max(frame.distance <= ((_f = ring === null || ring === void 0 ? void 0 : ring.nearDistance) !== null && _f !== void 0 ? _f : 100) ? ((_g = ring === null || ring === void 0 ? void 0 : ring.nearRadius) !== null && _g !== void 0 ? _g : 10) : 0, hovered ? ((_h = ring === null || ring === void 0 ? void 0 : ring.hoverRadius) !== null && _h !== void 0 ? _h : (this.Transient && !this.Persistent ? 15.4 : 22)) : 0));
|
|
6829
|
+
const targetRadius = normalRadius + (15.4 - normalRadius) * cursorMotion.amount;
|
|
6830
|
+
const now = Date.now();
|
|
6831
|
+
const duration = (_j = ring === null || ring === void 0 ? void 0 : ring.transitionDuration) !== null && _j !== void 0 ? _j : 200;
|
|
6832
|
+
const sharedRing = this.Transient && !this.Persistent && this.hoverFade.to === 1 ? this.hoverRingState : undefined;
|
|
6833
|
+
let ringAnimation = sharedRing ? sharedRing.animation : this.ringAnimation;
|
|
6834
|
+
if (!ringAnimation) {
|
|
6835
|
+
ringAnimation = { target: 0, start: now, outer: 2.5, inner: 0, fromOuter: 2.5, fromInner: 0 };
|
|
6836
|
+
}
|
|
6837
|
+
const animateRing = () => {
|
|
6838
|
+
const progress = duration > 0 ? Math.min(1, Math.max(0, (now - ringAnimation.start) / duration)) : 1;
|
|
6839
|
+
const eased = progress * progress * (3 - 2 * progress);
|
|
6840
|
+
ringAnimation.outer = ringAnimation.fromOuter + ((ringAnimation.target || 2.5) - ringAnimation.fromOuter) * eased;
|
|
6841
|
+
ringAnimation.inner = ringAnimation.fromInner + (Math.max(0, ringAnimation.target - 2) - ringAnimation.fromInner) * eased;
|
|
6842
|
+
return progress;
|
|
6843
|
+
};
|
|
6844
|
+
animateRing();
|
|
6845
|
+
if (ringAnimation.target !== targetRadius) {
|
|
6846
|
+
ringAnimation = {
|
|
6847
|
+
...ringAnimation,
|
|
6848
|
+
target: targetRadius,
|
|
6849
|
+
start: now,
|
|
6850
|
+
fromOuter: ringAnimation.outer,
|
|
6851
|
+
fromInner: ringAnimation.inner
|
|
6852
|
+
};
|
|
6853
|
+
}
|
|
6854
|
+
// Animate the hole and stem together; no CSS transition may lag behind a moving world anchor.
|
|
6855
|
+
if (animateRing() < 1 && (ringAnimation.fromOuter !== (targetRadius || 2.5) || ringAnimation.fromInner !== Math.max(0, targetRadius - 2))) {
|
|
6856
|
+
this.viewer.scene.requestRender();
|
|
6857
|
+
}
|
|
6858
|
+
this.ringAnimation = ringAnimation;
|
|
6859
|
+
if (sharedRing) {
|
|
6860
|
+
sharedRing.animation = ringAnimation;
|
|
6861
|
+
}
|
|
6862
|
+
const radius = ringAnimation.inner > 0 ? ringAnimation.outer : 0;
|
|
6863
|
+
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);
|
|
6864
|
+
const position = { x: (stem || frame).x, y: (stem || frame).y };
|
|
6865
|
+
const width = ele.offsetWidth / coordinates.scaleX;
|
|
6866
|
+
const height = ele.offsetHeight / coordinates.scaleY;
|
|
6867
|
+
if (leader && placement.textSide === "left") {
|
|
6868
|
+
position.x = Math.max(0, Math.min(frame.anchorX - width, this.viewer.canvas.clientWidth - width));
|
|
6869
|
+
}
|
|
6870
|
+
const gap = (_l = (_k = this.options.pointerAvoidance) === null || _k === void 0 ? void 0 : _k.gap) !== null && _l !== void 0 ? _l : 12;
|
|
6871
|
+
const containsPointer = (x, y, margin) => {
|
|
6872
|
+
return pointer && pointer.x >= x - margin && pointer.x <= x + width + margin && pointer.y >= y - margin && pointer.y <= y + height + margin;
|
|
6873
|
+
};
|
|
6874
|
+
const passive = !selectOnClick || !this.visualRegister;
|
|
6875
|
+
if (passive && ((_m = this.options.pointerAvoidance) === null || _m === void 0 ? void 0 : _m.enabled) !== false && pointer &&
|
|
6876
|
+
(containsPointer(position.x, position.y, gap) || containsPointer(position.x + displacement.x, position.y + displacement.y, gap))) {
|
|
6877
|
+
if (containsPointer(position.x + displacement.x, position.y + displacement.y, 0)) {
|
|
6878
|
+
// Choose against the original box and retain the offset until the pointer leaves both boxes.
|
|
6879
|
+
const candidates = [
|
|
6880
|
+
{ x: 0, y: pointer.y - gap - height - position.y },
|
|
6881
|
+
{ x: 0, y: pointer.y + gap - position.y },
|
|
6882
|
+
{ x: pointer.x - gap - width - position.x, y: 0 },
|
|
6883
|
+
{ x: pointer.x + gap - position.x, y: 0 }
|
|
6884
|
+
].filter(offset => position.x + offset.x >= 0 && position.y + offset.y >= 0 &&
|
|
6885
|
+
position.x + offset.x + width <= this.viewer.canvas.clientWidth && position.y + offset.y + height <= this.viewer.canvas.clientHeight)
|
|
6886
|
+
.sort((a, b) => Math.hypot(a.x, a.y) - Math.hypot(b.x, b.y));
|
|
6887
|
+
displacement = candidates[0] || { x: 0, y: 0 };
|
|
5874
6888
|
}
|
|
5875
|
-
// Position the label above the line end point.
|
|
5876
|
-
this.label.style.left = `${lineEndPos2d.x}px`;
|
|
5877
|
-
this.label.style.top = `${lineEndPos2d.y}px`;
|
|
5878
|
-
// Update line position and size.
|
|
5879
|
-
const dx = lineEndPos2d.x - lineStartPos2d.x;
|
|
5880
|
-
const dy = lineEndPos2d.y - lineStartPos2d.y;
|
|
5881
|
-
const length = Math.sqrt(dx * dx + dy * dy);
|
|
5882
|
-
const angle = Math.atan2(dy, dx) - Math.PI / 2;
|
|
5883
|
-
this.line.style.left = `${lineStartPos2d.x}px`;
|
|
5884
|
-
this.line.style.top = `${lineStartPos2d.y}px`;
|
|
5885
|
-
this.line.style.height = `${length}px`;
|
|
5886
|
-
this.line.style.transform = `rotate(${angle}rad)`;
|
|
5887
|
-
this.line.style.transformOrigin = 'top center';
|
|
5888
6889
|
}
|
|
5889
6890
|
else {
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
6891
|
+
displacement = { x: 0, y: 0 };
|
|
6892
|
+
}
|
|
6893
|
+
const nudgeDuration = (_p = (_o = this.options.pointerAvoidance) === null || _o === void 0 ? void 0 : _o.transitionDuration) !== null && _p !== void 0 ? _p : 200;
|
|
6894
|
+
const animateNudge = () => {
|
|
6895
|
+
const progress = now < nudge.start ? 0 : nudgeDuration > 0 ? Math.min(1, (now - nudge.start) / nudgeDuration) : 1;
|
|
6896
|
+
const eased = progress * progress * (3 - 2 * progress);
|
|
6897
|
+
nudge.x = nudge.fromX + (nudge.targetX - nudge.fromX) * eased;
|
|
6898
|
+
nudge.y = nudge.fromY + (nudge.targetY - nudge.fromY) * eased;
|
|
6899
|
+
return progress;
|
|
6900
|
+
};
|
|
6901
|
+
animateNudge();
|
|
6902
|
+
if (nudge.targetX !== displacement.x || nudge.targetY !== displacement.y) {
|
|
6903
|
+
nudge = {
|
|
6904
|
+
...nudge,
|
|
6905
|
+
fromX: nudge.x,
|
|
6906
|
+
fromY: nudge.y,
|
|
6907
|
+
targetX: displacement.x,
|
|
6908
|
+
targetY: displacement.y,
|
|
6909
|
+
start: now + ((_r = (_q = this.options.pointerAvoidance) === null || _q === void 0 ? void 0 : _q.delay) !== null && _r !== void 0 ? _r : 180)
|
|
6910
|
+
};
|
|
6911
|
+
}
|
|
6912
|
+
if (animateNudge() < 1 && (nudge.fromX !== nudge.targetX || nudge.fromY !== nudge.targetY)) {
|
|
6913
|
+
this.viewer.scene.requestRender();
|
|
6914
|
+
}
|
|
6915
|
+
position.x += nudge.x;
|
|
6916
|
+
position.y += nudge.y;
|
|
6917
|
+
ele.style.left = `${coordinates.x + position.x * coordinates.scaleX}px`;
|
|
6918
|
+
ele.style.top = `${coordinates.y + position.y * coordinates.scaleY}px`;
|
|
6919
|
+
const clickTarget = content.querySelector('[role="button"]');
|
|
6920
|
+
if (clickTarget) {
|
|
6921
|
+
clickTarget.setAttribute("aria-label", placement.members.length ? `Select ${placement.entityIds.length} entities` : `Select ${(_t = (_s = this.options.text) !== null && _s !== void 0 ? _s : text) !== null && _t !== void 0 ? _t : (_u = this.rego) === null || _u === void 0 ? void 0 : _u.entityId}`);
|
|
6922
|
+
}
|
|
6923
|
+
if (leader) {
|
|
6924
|
+
const nodeRadius = ringAnimation.outer;
|
|
6925
|
+
const anchor = this.anchor;
|
|
6926
|
+
anchor.style.left = `${coordinates.x + (frame.anchorX - nodeRadius) * coordinates.scaleX}px`;
|
|
6927
|
+
anchor.style.top = `${coordinates.y + (frame.anchorY - nodeRadius) * coordinates.scaleY}px`;
|
|
6928
|
+
anchor.style.width = `${nodeRadius * 2 * coordinates.scaleX}px`;
|
|
6929
|
+
anchor.style.height = `${nodeRadius * 2 * coordinates.scaleY}px`;
|
|
6930
|
+
anchor.style.boxSizing = "border-box";
|
|
6931
|
+
anchor.style.background = "transparent";
|
|
6932
|
+
const svg = anchor.firstElementChild;
|
|
6933
|
+
svg.setAttribute("viewBox", `0 0 ${nodeRadius * 2} ${nodeRadius * 2}`);
|
|
6934
|
+
const circle = svg.firstElementChild;
|
|
6935
|
+
circle.setAttribute("cx", String(nodeRadius));
|
|
6936
|
+
circle.setAttribute("cy", String(nodeRadius));
|
|
6937
|
+
circle.setAttribute("r", String((nodeRadius + ringAnimation.inner) / 2));
|
|
6938
|
+
circle.setAttribute("stroke", this.options.leaderColor || "rgba(255, 255, 255, 0.8)");
|
|
6939
|
+
circle.setAttribute("stroke-width", String(nodeRadius - ringAnimation.inner));
|
|
6940
|
+
anchor.style.boxShadow = radius ? "none" : "0 0 5px rgba(0, 0, 0, 0.3)";
|
|
6941
|
+
anchor.style.opacity = String(opacity * (normalLeader ? 1 : cursorMotion.amount));
|
|
6942
|
+
anchor.style.zIndex = String(placement.zIndex);
|
|
6943
|
+
// The stem starts at the rim, never across the transparent centre, even after passive displacement.
|
|
6944
|
+
const endX = Math.max(position.x, Math.min(frame.anchorX, position.x + width));
|
|
6945
|
+
const endY = frame.anchorY < position.y ? position.y : frame.anchorY > position.y + height ? position.y + height : frame.anchorY;
|
|
6946
|
+
const dx = endX - frame.anchorX, dy = endY - frame.anchorY;
|
|
6947
|
+
const length = Math.hypot(dx, dy);
|
|
6948
|
+
const leaderAngle = Math.atan2(dy, dx);
|
|
6949
|
+
const pointerDx = pointer ? pointer.x - frame.anchorX : 0;
|
|
6950
|
+
const pointerDy = pointer ? pointer.y - frame.anchorY : 0;
|
|
6951
|
+
const desiredAngle = Math.hypot(pointerDx, pointerDy) > 0.5 ? Math.atan2(pointerDy, pointerDx) + Math.PI - leaderAngle : 0;
|
|
6952
|
+
const wrappedAngle = Math.atan2(Math.sin(desiredAngle), Math.cos(desiredAngle));
|
|
6953
|
+
// Keep the stem inside the 126-degree arc, away from antialiased endpoints.
|
|
6954
|
+
const arcFraction = 0.35;
|
|
6955
|
+
const rotationLimit = Math.PI * arcFraction - Math.PI / 30;
|
|
6956
|
+
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((_v = ringAnimation.arcOffset) !== null && _v !== void 0 ? _v : 0);
|
|
6957
|
+
const targetOpen = cursorMotion.target || (hovered && (ring === null || ring === void 0 ? void 0 : ring.enabled) !== false && targetRadius > 0) ? 1 : 0;
|
|
6958
|
+
const elapsed = Math.min(32, Math.max(0, now - ((_w = ringAnimation.arcTime) !== null && _w !== void 0 ? _w : now)));
|
|
6959
|
+
const blend = duration > 0 ? 1 - Math.exp(-elapsed / (duration / 3)) : 1;
|
|
6960
|
+
const approach = (value, target) => Math.abs(value - target) < 0.001 ? target : value + (target - value) * blend;
|
|
6961
|
+
ringAnimation.arcOffset = approach((_x = ringAnimation.arcOffset) !== null && _x !== void 0 ? _x : 0, targetOffset);
|
|
6962
|
+
ringAnimation.arcOpen = approach((_y = ringAnimation.arcOpen) !== null && _y !== void 0 ? _y : 0, targetOpen);
|
|
6963
|
+
ringAnimation.arcTime = now;
|
|
6964
|
+
if (ringAnimation.arcOffset !== targetOffset || ringAnimation.arcOpen !== targetOpen) {
|
|
6965
|
+
this.viewer.scene.requestRender();
|
|
6966
|
+
}
|
|
6967
|
+
const circumference = Math.PI * (nodeRadius + ringAnimation.inner);
|
|
6968
|
+
const filledFraction = 1 - ringAnimation.arcOpen * (1 - arcFraction);
|
|
6969
|
+
circle.setAttribute("stroke-dasharray", `${circumference * filledFraction} ${circumference * (1 - filledFraction)}`);
|
|
6970
|
+
circle.setAttribute("transform", `rotate(${(leaderAngle + ringAnimation.arcOffset - Math.PI * filledFraction) * 180 / Math.PI} ${nodeRadius} ${nodeRadius})`);
|
|
6971
|
+
const cut = Math.min(radius, length);
|
|
6972
|
+
const startX = frame.anchorX + (length ? dx / length * cut : 0);
|
|
6973
|
+
const startY = frame.anchorY + (length ? dy / length * cut : 0);
|
|
6974
|
+
const screenDx = (endX - startX) * coordinates.scaleX;
|
|
6975
|
+
const screenDy = (endY - startY) * coordinates.scaleY;
|
|
6976
|
+
lineEle.style.width = `${2 * coordinates.scaleX}px`;
|
|
6977
|
+
lineEle.style.left = `${coordinates.x + (startX - 1) * coordinates.scaleX}px`;
|
|
6978
|
+
lineEle.style.top = `${coordinates.y + startY * coordinates.scaleY}px`;
|
|
6979
|
+
lineEle.style.height = `${Math.hypot(screenDx, screenDy)}px`;
|
|
6980
|
+
lineEle.style.transform = `rotate(${Math.atan2(screenDy, screenDx) - Math.PI / 2}rad)`;
|
|
6981
|
+
lineEle.style.boxShadow = radius ? "none" : "0 0 5px rgba(0, 0, 0, 0.3)";
|
|
6982
|
+
lineEle.style.transformOrigin = "top center";
|
|
6983
|
+
lineEle.style.opacity = String(opacity * (normalLeader ? 1 : cursorMotion.amount));
|
|
6984
|
+
lineEle.style.zIndex = String(placement.zIndex);
|
|
5893
6985
|
}
|
|
5894
6986
|
};
|
|
5895
|
-
|
|
5896
|
-
|
|
6987
|
+
ele.style.display = "flex";
|
|
6988
|
+
ele.style.visibility = "hidden";
|
|
6989
|
+
this.renderRemoval = layer.Add({ project, apply });
|
|
5897
6990
|
// If terrain changes then we'll re-call createLabel as the position may have changed.
|
|
5898
6991
|
let terrTimeout = null;
|
|
5899
6992
|
this.terrChangedRemoval = this.viewer.scene.terrainProviderChanged.addEventListener(() => {
|
|
@@ -5913,6 +7006,9 @@
|
|
|
5913
7006
|
* Removes label from the viewer and unsubscribes from events.
|
|
5914
7007
|
*/
|
|
5915
7008
|
removeLabel() {
|
|
7009
|
+
var _a;
|
|
7010
|
+
(_a = this.anchor) === null || _a === void 0 ? void 0 : _a.remove();
|
|
7011
|
+
this.anchor = null;
|
|
5916
7012
|
if (this.label &&
|
|
5917
7013
|
this.label.parentElement) {
|
|
5918
7014
|
this.label.parentElement.removeChild(this.label);
|
|
@@ -5938,16 +7034,44 @@
|
|
|
5938
7034
|
* If one exists then the action is ignored.
|
|
5939
7035
|
*/
|
|
5940
7036
|
function Attach(params) {
|
|
5941
|
-
|
|
5942
|
-
|
|
7037
|
+
var _a, _b, _c;
|
|
7038
|
+
const { rego, viewer, pos3d, visualRegister, api, options, groupId } = params;
|
|
7039
|
+
if (!rego || !viewer) {
|
|
5943
7040
|
return;
|
|
5944
7041
|
}
|
|
7042
|
+
if (params.persistent == null && visualRegister) {
|
|
7043
|
+
const group = visualRegister.GetLabelGroupFor(rego.entityId, rego.menuItemId);
|
|
7044
|
+
if (group || visualRegister.GetIsLabelled({ entityId: rego.entityId, menuItemId: rego.menuItemId })) {
|
|
7045
|
+
return Attach({
|
|
7046
|
+
...params,
|
|
7047
|
+
pos3d: undefined,
|
|
7048
|
+
options: (_a = group === null || group === void 0 ? void 0 : group.options) !== null && _a !== void 0 ? _a : options,
|
|
7049
|
+
groupId: (_b = group === null || group === void 0 ? void 0 : group.groupId) !== null && _b !== void 0 ? _b : groupId,
|
|
7050
|
+
persistent: true
|
|
7051
|
+
});
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
if (rego[EntityLabel.ATTACH_KEY]) {
|
|
7055
|
+
// Legacy hover callers omit ownership/options and must not reconfigure a register-owned label.
|
|
7056
|
+
if (rego[EntityLabel.ATTACH_KEY].Persistent && params.persistent !== true && !groupId) {
|
|
7057
|
+
return rego[EntityLabel.ATTACH_KEY];
|
|
7058
|
+
}
|
|
7059
|
+
rego[EntityLabel.ATTACH_KEY].Persistent = (_c = params.persistent) !== null && _c !== void 0 ? _c : Boolean(groupId);
|
|
7060
|
+
rego[EntityLabel.ATTACH_KEY].Configure(options, groupId);
|
|
7061
|
+
return rego[EntityLabel.ATTACH_KEY];
|
|
7062
|
+
}
|
|
5945
7063
|
rego[EntityLabel.ATTACH_KEY] = new Label({
|
|
5946
7064
|
rego,
|
|
5947
7065
|
viewer,
|
|
5948
7066
|
pos3d,
|
|
5949
7067
|
visualRegister,
|
|
5950
|
-
api
|
|
7068
|
+
api,
|
|
7069
|
+
options,
|
|
7070
|
+
groupId,
|
|
7071
|
+
persistent: params.persistent,
|
|
7072
|
+
transient: params.transient,
|
|
7073
|
+
hoverRingState: params.hoverRingState,
|
|
7074
|
+
visible: params.visible
|
|
5951
7075
|
});
|
|
5952
7076
|
return rego[EntityLabel.ATTACH_KEY];
|
|
5953
7077
|
}
|
|
@@ -5962,12 +7086,19 @@
|
|
|
5962
7086
|
if (!rego && label) {
|
|
5963
7087
|
rego = label.Rego;
|
|
5964
7088
|
}
|
|
7089
|
+
if (label && label !== (rego === null || rego === void 0 ? void 0 : rego[EntityLabel.ATTACH_KEY])) {
|
|
7090
|
+
if (!label.Persistent || params.force)
|
|
7091
|
+
label.Dispose();
|
|
7092
|
+
return;
|
|
7093
|
+
}
|
|
5965
7094
|
if (!rego || !rego[EntityLabel.ATTACH_KEY]) {
|
|
5966
7095
|
if (label) {
|
|
5967
7096
|
(_a = label.Dispose) === null || _a === void 0 ? void 0 : _a.call(label);
|
|
5968
7097
|
}
|
|
5969
7098
|
return;
|
|
5970
7099
|
}
|
|
7100
|
+
if (rego[EntityLabel.ATTACH_KEY].Persistent && !params.force)
|
|
7101
|
+
return;
|
|
5971
7102
|
(_c = (_b = rego[EntityLabel.ATTACH_KEY]).Dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
5972
7103
|
rego[EntityLabel.ATTACH_KEY] = null;
|
|
5973
7104
|
}
|
|
@@ -5987,6 +7118,537 @@
|
|
|
5987
7118
|
EntityLabel.GetLabel = GetLabel;
|
|
5988
7119
|
})(exports.EntityLabel || (exports.EntityLabel = {}));
|
|
5989
7120
|
|
|
7121
|
+
(function (EntityLabelGroup) {
|
|
7122
|
+
/*
|
|
7123
|
+
* Keeps the query response useful even when the Entity has no loaded visual yet.
|
|
7124
|
+
*/
|
|
7125
|
+
function FromEntity(entity) {
|
|
7126
|
+
var _a, _b, _c, _d;
|
|
7127
|
+
const location = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.Location;
|
|
7128
|
+
const pivot = (_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.GeometryWorldPivot;
|
|
7129
|
+
let cartographic;
|
|
7130
|
+
if ((pivot === null || pivot === void 0 ? void 0 : pivot.length) >= 3 && pivot.every(Number.isFinite)) {
|
|
7131
|
+
cartographic = Cesium.Cartographic.fromCartesian(Cesium.Cartesian3.fromArray(pivot));
|
|
7132
|
+
}
|
|
7133
|
+
return {
|
|
7134
|
+
entityId: (_c = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _c === void 0 ? void 0 : _c.ID,
|
|
7135
|
+
text: (_d = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _d === void 0 ? void 0 : _d.Name,
|
|
7136
|
+
longitude: cartographic ? Cesium.Math.toDegrees(cartographic.longitude) : location === null || location === void 0 ? void 0 : location.longitude,
|
|
7137
|
+
latitude: cartographic ? Cesium.Math.toDegrees(cartographic.latitude) : location === null || location === void 0 ? void 0 : location.latitude,
|
|
7138
|
+
altitude: cartographic ? cartographic.height : location === null || location === void 0 ? void 0 : location.altitude,
|
|
7139
|
+
entity
|
|
7140
|
+
};
|
|
7141
|
+
}
|
|
7142
|
+
EntityLabelGroup.FromEntity = FromEntity;
|
|
7143
|
+
/**
|
|
7144
|
+
* Returns if we need to resolve Entity data to create the label data.
|
|
7145
|
+
*/
|
|
7146
|
+
function NeedsEntityData(options) {
|
|
7147
|
+
var _a;
|
|
7148
|
+
if (!options) {
|
|
7149
|
+
return false;
|
|
7150
|
+
}
|
|
7151
|
+
if ((_a = options.attributes) === null || _a === void 0 ? void 0 : _a.length) {
|
|
7152
|
+
return true;
|
|
7153
|
+
}
|
|
7154
|
+
return [
|
|
7155
|
+
options.text, options.icon, options.iconUrl, options.iconClass,
|
|
7156
|
+
options.iconColor, options.iconStatus, options.iconPriority, options.iconScale
|
|
7157
|
+
].some(Array.isArray);
|
|
7158
|
+
}
|
|
7159
|
+
EntityLabelGroup.NeedsEntityData = NeedsEntityData;
|
|
7160
|
+
// How many entities to read at once, so a long hand-picked list does not arrive as a burst.
|
|
7161
|
+
const HYDRATE_AT_ONCE = 8;
|
|
7162
|
+
/*
|
|
7163
|
+
* Reads the entities behind items that name one without carrying it.
|
|
7164
|
+
*/
|
|
7165
|
+
async function Hydrate(items, api, signal) {
|
|
7166
|
+
if (!api) {
|
|
7167
|
+
return items;
|
|
7168
|
+
}
|
|
7169
|
+
const hydrated = items.slice();
|
|
7170
|
+
for (let start = 0; start < hydrated.length; start += HYDRATE_AT_ONCE) {
|
|
7171
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
7172
|
+
return hydrated;
|
|
7173
|
+
}
|
|
7174
|
+
await Promise.all(hydrated.slice(start, start + HYDRATE_AT_ONCE).map(async (item, at) => {
|
|
7175
|
+
if (!(item === null || item === void 0 ? void 0 : item.entityId) || item.entity) {
|
|
7176
|
+
return;
|
|
7177
|
+
}
|
|
7178
|
+
try {
|
|
7179
|
+
const { entity } = await BModels.Entity.Get({ api, entityId: item.entityId, migrated: true });
|
|
7180
|
+
if (entity) {
|
|
7181
|
+
hydrated[start + at] = { ...item, entity };
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
catch {
|
|
7185
|
+
// Rip.
|
|
7186
|
+
}
|
|
7187
|
+
}));
|
|
7188
|
+
}
|
|
7189
|
+
return hydrated;
|
|
7190
|
+
}
|
|
7191
|
+
EntityLabelGroup.Hydrate = Hydrate;
|
|
7192
|
+
/*
|
|
7193
|
+
* Uses the existing DataLab grammar, discarding actions and projections that cannot return Entities.
|
|
7194
|
+
*/
|
|
7195
|
+
async function Loader(source, api, signal, hydrate) {
|
|
7196
|
+
var _a;
|
|
7197
|
+
var _b;
|
|
7198
|
+
if (source.type === "provider") {
|
|
7199
|
+
return (offset, limit, signal) => source.loadPage({ offset, limit, signal });
|
|
7200
|
+
}
|
|
7201
|
+
if (source.type === "entityIds" || source.type === "json") {
|
|
7202
|
+
const items = (source.type === "entityIds" ? source.entityIds.map(entityId => ({ entityId })) :
|
|
7203
|
+
typeof source.items === "string" ? JSON.parse(source.items) : source.items);
|
|
7204
|
+
if (!Array.isArray(items)) {
|
|
7205
|
+
throw new Error("Label JSON must be an array of label items");
|
|
7206
|
+
}
|
|
7207
|
+
return async (offset, limit, signal) => {
|
|
7208
|
+
const page = items.slice(offset, offset + limit);
|
|
7209
|
+
return {
|
|
7210
|
+
items: hydrate ? await Hydrate(page, api, signal) : page,
|
|
7211
|
+
hasMore: offset + limit < items.length
|
|
7212
|
+
};
|
|
7213
|
+
};
|
|
7214
|
+
}
|
|
7215
|
+
if (!api) {
|
|
7216
|
+
throw new Error("DataLab label sources require API getters on the visual register");
|
|
7217
|
+
}
|
|
7218
|
+
let query;
|
|
7219
|
+
if (source.type === "queryId") {
|
|
7220
|
+
const saved = (await BModels.DataLab.Get({ api, queryId: source.queryId, req: { noCache: true, abortSignal: signal } })).query;
|
|
7221
|
+
const selection = (_a = saved === null || saved === void 0 ? void 0 : saved.PrimarySelectionCriteria) !== null && _a !== void 0 ? _a : saved === null || saved === void 0 ? void 0 : saved.PrimarySelection;
|
|
7222
|
+
if (!selection) {
|
|
7223
|
+
throw new Error("Saved label query has no selection criteria");
|
|
7224
|
+
}
|
|
7225
|
+
query = { PrimarySelection: selection };
|
|
7226
|
+
}
|
|
7227
|
+
else {
|
|
7228
|
+
query = typeof source.query === "string" ? JSON.parse(source.query) : source.query;
|
|
7229
|
+
}
|
|
7230
|
+
if (!(query === null || query === void 0 ? void 0 : query.PrimarySelection)) {
|
|
7231
|
+
throw new Error("Label query requires PrimarySelection");
|
|
7232
|
+
}
|
|
7233
|
+
query = JSON.parse(JSON.stringify(query));
|
|
7234
|
+
delete query.Action;
|
|
7235
|
+
query.PrimarySelection.Select = { Type: BModels.DataLab.ESelectType.Entity };
|
|
7236
|
+
(_b = query.PrimarySelection).OrderBy || (_b.OrderBy = "Bruce/ID");
|
|
7237
|
+
query.Expand = query.Expand ? `${query.Expand},location` : "location";
|
|
7238
|
+
return async (offset, limit, signal) => {
|
|
7239
|
+
const response = await BModels.DataLab.Run({ api, query, skip: offset, load: limit, migrated: true, req: { noCache: true, abortSignal: signal } });
|
|
7240
|
+
const entities = response.entities || response.items || [];
|
|
7241
|
+
return {
|
|
7242
|
+
items: entities.map(FromEntity),
|
|
7243
|
+
hasMore: response.totalCount != null ? offset + entities.length < response.totalCount : entities.length === limit
|
|
7244
|
+
};
|
|
7245
|
+
};
|
|
7246
|
+
}
|
|
7247
|
+
EntityLabelGroup.Loader = Loader;
|
|
7248
|
+
/*
|
|
7249
|
+
* Snapshot settings without dropping Calculator's optional runtime function values.
|
|
7250
|
+
*/
|
|
7251
|
+
function copyOptions(value) {
|
|
7252
|
+
if (Array.isArray(value)) {
|
|
7253
|
+
return value.map(copyOptions);
|
|
7254
|
+
}
|
|
7255
|
+
if (value && typeof value === "object") {
|
|
7256
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, copyOptions(item)]));
|
|
7257
|
+
}
|
|
7258
|
+
return value;
|
|
7259
|
+
}
|
|
7260
|
+
/*
|
|
7261
|
+
* Evaluate source attributes during register refresh, never in the camera-frame layout loop.
|
|
7262
|
+
*/
|
|
7263
|
+
function resolveIcon(value, entity) {
|
|
7264
|
+
if (!Array.isArray(value))
|
|
7265
|
+
return value;
|
|
7266
|
+
try {
|
|
7267
|
+
return BModels.Calculator.GetString(value, entity || {});
|
|
7268
|
+
}
|
|
7269
|
+
catch {
|
|
7270
|
+
// An invalid expression on one item must not prevent the remaining labels from rendering.
|
|
7271
|
+
return null;
|
|
7272
|
+
}
|
|
7273
|
+
}
|
|
7274
|
+
/*
|
|
7275
|
+
* Owns membership independently of manual labelled states, with atomic replacement and stale-load cancellation.
|
|
7276
|
+
*/
|
|
7277
|
+
class Manager {
|
|
7278
|
+
constructor(register, changed = () => { }) {
|
|
7279
|
+
this.register = register;
|
|
7280
|
+
this.changed = changed;
|
|
7281
|
+
this.active = new Map();
|
|
7282
|
+
this.pending = new Map();
|
|
7283
|
+
this.standalone = new Map();
|
|
7284
|
+
this.standaloneItems = new Map();
|
|
7285
|
+
this.members = new Map();
|
|
7286
|
+
this.definitions = new Map();
|
|
7287
|
+
this.visibility = new Map();
|
|
7288
|
+
this.errors = new Map();
|
|
7289
|
+
}
|
|
7290
|
+
notify() {
|
|
7291
|
+
try {
|
|
7292
|
+
this.changed();
|
|
7293
|
+
}
|
|
7294
|
+
catch (error) {
|
|
7295
|
+
console.error("Label group observer failed", error);
|
|
7296
|
+
}
|
|
7297
|
+
}
|
|
7298
|
+
Refresh(id) {
|
|
7299
|
+
const definition = this.definitions.get(id);
|
|
7300
|
+
if (!definition)
|
|
7301
|
+
return Promise.reject(new Error(`Unknown label group: ${id}`));
|
|
7302
|
+
return this.Set({ ...definition, visible: this.visibility.get(id) });
|
|
7303
|
+
}
|
|
7304
|
+
SetVisible(id, visible) {
|
|
7305
|
+
var _a;
|
|
7306
|
+
if (!this.definitions.has(id))
|
|
7307
|
+
return false;
|
|
7308
|
+
if (this.visibility.get(id) === visible)
|
|
7309
|
+
return true;
|
|
7310
|
+
this.visibility.set(id, visible);
|
|
7311
|
+
this.refresh(new Set(((_a = this.active.get(id)) === null || _a === void 0 ? void 0 : _a.items.keys()) || []));
|
|
7312
|
+
this.notify();
|
|
7313
|
+
return true;
|
|
7314
|
+
}
|
|
7315
|
+
async Set(definition) {
|
|
7316
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
7317
|
+
if (!(definition === null || definition === void 0 ? void 0 : definition.id) || !definition.source) {
|
|
7318
|
+
throw new Error("Label group requires id and source");
|
|
7319
|
+
}
|
|
7320
|
+
definition = { ...definition, options: copyOptions(definition.options) };
|
|
7321
|
+
const pageSize = (_a = definition.pageSize) !== null && _a !== void 0 ? _a : 500;
|
|
7322
|
+
const maximum = (_b = definition.maxItems) !== null && _b !== void 0 ? _b : 50000;
|
|
7323
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || !Number.isInteger(maximum) || maximum < 1) {
|
|
7324
|
+
throw new Error("Label pageSize and maxItems must be positive integers");
|
|
7325
|
+
}
|
|
7326
|
+
ValidateOptions(definition.options);
|
|
7327
|
+
(_c = this.pending.get(definition.id)) === null || _c === void 0 ? void 0 : _c.abort();
|
|
7328
|
+
const controller = new AbortController();
|
|
7329
|
+
this.pending.set(definition.id, controller);
|
|
7330
|
+
this.definitions.set(definition.id, definition);
|
|
7331
|
+
const wasVisible = this.visibility.get(definition.id);
|
|
7332
|
+
this.visibility.set(definition.id, (_e = (_d = definition.visible) !== null && _d !== void 0 ? _d : this.visibility.get(definition.id)) !== null && _e !== void 0 ? _e : true);
|
|
7333
|
+
if (wasVisible != null && wasVisible !== this.visibility.get(definition.id)) {
|
|
7334
|
+
this.refresh(new Set(((_f = this.active.get(definition.id)) === null || _f === void 0 ? void 0 : _f.items.keys()) || []));
|
|
7335
|
+
}
|
|
7336
|
+
this.errors.delete(definition.id);
|
|
7337
|
+
this.notify();
|
|
7338
|
+
const cancelled = () => ({ id: definition.id, entityIds: [], truncated: false, cancelled: true });
|
|
7339
|
+
const items = new Map();
|
|
7340
|
+
let truncated = false;
|
|
7341
|
+
try {
|
|
7342
|
+
const load = await Loader(definition.source, (_g = this.register.ApiGetters) === null || _g === void 0 ? void 0 : _g.GetBruceApi(), controller.signal, NeedsEntityData(definition.options));
|
|
7343
|
+
let offset = 0;
|
|
7344
|
+
for (let pageNumber = 0;; pageNumber++) {
|
|
7345
|
+
if (controller.signal.aborted || this.register.Disposed) {
|
|
7346
|
+
return cancelled();
|
|
7347
|
+
}
|
|
7348
|
+
if (pageNumber >= 10000) {
|
|
7349
|
+
throw new Error("Label source exceeded 10000 pages");
|
|
7350
|
+
}
|
|
7351
|
+
const page = await load(offset, Math.min(pageSize, maximum - items.size), controller.signal);
|
|
7352
|
+
if (controller.signal.aborted || this.register.Disposed)
|
|
7353
|
+
return cancelled();
|
|
7354
|
+
if (!Array.isArray(page === null || page === void 0 ? void 0 : page.items)) {
|
|
7355
|
+
throw new Error("Label source returned an invalid page");
|
|
7356
|
+
}
|
|
7357
|
+
for (const item of page.items) {
|
|
7358
|
+
if (!item || typeof item.entityId !== "string" || !item.entityId) {
|
|
7359
|
+
throw new Error("Label item requires entityId");
|
|
7360
|
+
}
|
|
7361
|
+
if (!items.has(item.entityId) && items.size >= maximum) {
|
|
7362
|
+
truncated = true;
|
|
7363
|
+
break;
|
|
7364
|
+
}
|
|
7365
|
+
items.set(item.entityId, item);
|
|
7366
|
+
}
|
|
7367
|
+
if (!page.hasMore) {
|
|
7368
|
+
break;
|
|
7369
|
+
}
|
|
7370
|
+
if (items.size >= maximum) {
|
|
7371
|
+
truncated = true;
|
|
7372
|
+
break;
|
|
7373
|
+
}
|
|
7374
|
+
const next = (_h = page.nextOffset) !== null && _h !== void 0 ? _h : offset + page.items.length;
|
|
7375
|
+
if (!Number.isSafeInteger(next) || next <= offset) {
|
|
7376
|
+
throw new Error("Label source pagination did not advance");
|
|
7377
|
+
}
|
|
7378
|
+
offset = next;
|
|
7379
|
+
}
|
|
7380
|
+
const previous = this.active.get(definition.id);
|
|
7381
|
+
const affected = new Set([...((previous === null || previous === void 0 ? void 0 : previous.items.keys()) || []), ...items.keys()]);
|
|
7382
|
+
this.unindex(definition.id);
|
|
7383
|
+
// Reinsertion makes the most recently committed matching group the presentation owner.
|
|
7384
|
+
this.active.delete(definition.id);
|
|
7385
|
+
this.active.set(definition.id, { definition, items, truncated });
|
|
7386
|
+
for (const id of items.keys()) {
|
|
7387
|
+
if (!this.members.has(id)) {
|
|
7388
|
+
this.members.set(id, new Set());
|
|
7389
|
+
}
|
|
7390
|
+
this.members.get(id).add(definition.id);
|
|
7391
|
+
}
|
|
7392
|
+
this.refresh(affected);
|
|
7393
|
+
return { id: definition.id, entityIds: Array.from(items.keys()), truncated, cancelled: false };
|
|
7394
|
+
}
|
|
7395
|
+
catch (error) {
|
|
7396
|
+
if (controller.signal.aborted || this.register.Disposed) {
|
|
7397
|
+
return cancelled();
|
|
7398
|
+
}
|
|
7399
|
+
this.errors.set(definition.id, error instanceof Error ? error.message : String(error));
|
|
7400
|
+
throw error;
|
|
7401
|
+
}
|
|
7402
|
+
finally {
|
|
7403
|
+
if (this.pending.get(definition.id) === controller) {
|
|
7404
|
+
this.pending.delete(definition.id);
|
|
7405
|
+
this.notify();
|
|
7406
|
+
}
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
Get() {
|
|
7410
|
+
return Array.from(this.definitions.keys(), id => {
|
|
7411
|
+
var _a;
|
|
7412
|
+
const group = this.active.get(id);
|
|
7413
|
+
return {
|
|
7414
|
+
id,
|
|
7415
|
+
entityIds: Array.from((group === null || group === void 0 ? void 0 : group.items.keys()) || []),
|
|
7416
|
+
truncated: (_a = group === null || group === void 0 ? void 0 : group.truncated) !== null && _a !== void 0 ? _a : false,
|
|
7417
|
+
cancelled: false,
|
|
7418
|
+
visible: this.visibility.get(id) !== false,
|
|
7419
|
+
loading: this.pending.has(id),
|
|
7420
|
+
error: this.errors.get(id)
|
|
7421
|
+
};
|
|
7422
|
+
});
|
|
7423
|
+
}
|
|
7424
|
+
Has(entityId, menuItemId) {
|
|
7425
|
+
for (const id of this.members.get(entityId) || []) {
|
|
7426
|
+
const group = this.active.get(id);
|
|
7427
|
+
if (group && this.visibility.get(id) !== false && (!group.definition.menuItemId || group.definition.menuItemId === menuItemId)) {
|
|
7428
|
+
return true;
|
|
7429
|
+
}
|
|
7430
|
+
}
|
|
7431
|
+
return false;
|
|
7432
|
+
}
|
|
7433
|
+
Resolve(entityId, menuItemId) {
|
|
7434
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
7435
|
+
const ids = Array.from(this.members.get(entityId) || []).reverse();
|
|
7436
|
+
for (const id of ids) {
|
|
7437
|
+
const group = this.active.get(id);
|
|
7438
|
+
if (this.visibility.get(id) === false) {
|
|
7439
|
+
continue;
|
|
7440
|
+
}
|
|
7441
|
+
if (group.definition.menuItemId && group.definition.menuItemId !== menuItemId) {
|
|
7442
|
+
continue;
|
|
7443
|
+
}
|
|
7444
|
+
const item = group.items.get(entityId);
|
|
7445
|
+
const entity = (_a = item.entity) !== null && _a !== void 0 ? _a : { Bruce: { ID: entityId, Name: item.text } };
|
|
7446
|
+
let iconPriority = (_b = group.definition.options) === null || _b === void 0 ? void 0 : _b.iconPriority;
|
|
7447
|
+
if (Array.isArray(iconPriority)) {
|
|
7448
|
+
try {
|
|
7449
|
+
iconPriority = BModels.Calculator.GetNumber(iconPriority, entity);
|
|
7450
|
+
}
|
|
7451
|
+
catch {
|
|
7452
|
+
iconPriority = null;
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
let iconScale = (_c = group.definition.options) === null || _c === void 0 ? void 0 : _c.iconScale;
|
|
7456
|
+
if (Array.isArray(iconScale)) {
|
|
7457
|
+
try {
|
|
7458
|
+
iconScale = BModels.Calculator.GetNumber(iconScale, entity);
|
|
7459
|
+
}
|
|
7460
|
+
catch {
|
|
7461
|
+
iconScale = null;
|
|
7462
|
+
}
|
|
7463
|
+
if (!Number.isFinite(iconScale)) {
|
|
7464
|
+
iconScale = 1;
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
if (iconScale != null) {
|
|
7468
|
+
iconScale = Math.max(0, iconScale);
|
|
7469
|
+
}
|
|
7470
|
+
const textSetting = (_d = group.definition.options) === null || _d === void 0 ? void 0 : _d.text;
|
|
7471
|
+
let resolvedText = resolveIcon(textSetting, entity);
|
|
7472
|
+
const expression = Array.isArray(textSetting);
|
|
7473
|
+
if (expression && !(resolvedText === null || resolvedText === void 0 ? void 0 : resolvedText.trim())) {
|
|
7474
|
+
resolvedText = undefined;
|
|
7475
|
+
}
|
|
7476
|
+
const fallbackText = [item.text, (_e = entity.Bruce) === null || _e === void 0 ? void 0 : _e.Name, (_f = this.register.GetRego({ entityId, menuItemId })) === null || _f === void 0 ? void 0 : _f.name, entityId]
|
|
7477
|
+
.find(text => typeof text === "string" && text.trim().length > 0);
|
|
7478
|
+
const options = {
|
|
7479
|
+
...group.definition.options,
|
|
7480
|
+
text: resolvedText !== null && resolvedText !== void 0 ? resolvedText : fallbackText,
|
|
7481
|
+
iconScale: iconScale,
|
|
7482
|
+
icon: resolveIcon((_g = group.definition.options) === null || _g === void 0 ? void 0 : _g.icon, entity),
|
|
7483
|
+
iconUrl: resolveIcon((_h = group.definition.options) === null || _h === void 0 ? void 0 : _h.iconUrl, entity),
|
|
7484
|
+
iconClass: resolveIcon((_j = group.definition.options) === null || _j === void 0 ? void 0 : _j.iconClass, entity),
|
|
7485
|
+
iconColor: resolveIcon((_k = group.definition.options) === null || _k === void 0 ? void 0 : _k.iconColor, entity),
|
|
7486
|
+
iconBackground: (_l = group.definition.options) === null || _l === void 0 ? void 0 : _l.iconBackground,
|
|
7487
|
+
iconPriority: Number.isFinite(iconPriority) ? iconPriority : item.iconPriority,
|
|
7488
|
+
iconStatus: (_o = resolveIcon((_m = group.definition.options) === null || _m === void 0 ? void 0 : _m.iconStatus, entity)) !== null && _o !== void 0 ? _o : item.iconStatus
|
|
7489
|
+
};
|
|
7490
|
+
if (options.attributes && item.entity && !(expression && resolvedText != null)) {
|
|
7491
|
+
options.text = [
|
|
7492
|
+
(_r = (_p = options.text) !== null && _p !== void 0 ? _p : (_q = item.entity.Bruce) === null || _q === void 0 ? void 0 : _q.Name) !== null && _r !== void 0 ? _r : entityId,
|
|
7493
|
+
...options.attributes.map(path => BModels.Entity.GetValue({ entity: item.entity, path })).filter(value => value != null).map(String)
|
|
7494
|
+
].join("\n");
|
|
7495
|
+
}
|
|
7496
|
+
return { groupId: id, options, item };
|
|
7497
|
+
}
|
|
7498
|
+
return null;
|
|
7499
|
+
}
|
|
7500
|
+
RefreshEntity(entityId) {
|
|
7501
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
7502
|
+
const match = this.Resolve(entityId);
|
|
7503
|
+
const registered = this.register.GetRego({ entityId });
|
|
7504
|
+
if (!registered && match && this.standalone.has(entityId) && this.standaloneItems.get(entityId) === match.item) {
|
|
7505
|
+
this.standalone.get(entityId).Configure({ ...match.options, text: (_b = (_a = match.options.text) !== null && _a !== void 0 ? _a : match.item.text) !== null && _b !== void 0 ? _b : entityId }, match.groupId);
|
|
7506
|
+
return;
|
|
7507
|
+
}
|
|
7508
|
+
(_c = this.standalone.get(entityId)) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
7509
|
+
this.standalone.delete(entityId);
|
|
7510
|
+
this.standaloneItems.delete(entityId);
|
|
7511
|
+
if (this.register.Disposed || registered) {
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7514
|
+
if (!match) {
|
|
7515
|
+
return;
|
|
7516
|
+
}
|
|
7517
|
+
const item = match.item;
|
|
7518
|
+
if (![item.longitude, item.latitude, (_d = item.altitude) !== null && _d !== void 0 ? _d : 0].every(Number.isFinite) || Math.abs(item.latitude) > 90) {
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
const visual = new Cesium.Entity({
|
|
7522
|
+
position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.altitude || 0),
|
|
7523
|
+
point: { heightReference: Cesium.HeightReference.NONE, pixelSize: 0 }
|
|
7524
|
+
});
|
|
7525
|
+
this.standalone.set(entityId, new exports.EntityLabel.Label({
|
|
7526
|
+
viewer: this.register.Viewer,
|
|
7527
|
+
visualRegister: this.register,
|
|
7528
|
+
api: (_e = this.register.ApiGetters) === null || _e === void 0 ? void 0 : _e.GetBruceApi(),
|
|
7529
|
+
rego: { entityId, visual, name: item.text || entityId, priority: 0 },
|
|
7530
|
+
options: { ...match.options, text: (_g = (_f = match.options.text) !== null && _f !== void 0 ? _f : item.text) !== null && _g !== void 0 ? _g : entityId },
|
|
7531
|
+
groupId: match.groupId,
|
|
7532
|
+
visible: () => {
|
|
7533
|
+
const state = this.register.GetState({ entityId });
|
|
7534
|
+
return !state.hidden && (!this.register.GetIsIsolatedAny() || state.isolated || this.register.GetIsolationOpacity() != null);
|
|
7535
|
+
}
|
|
7536
|
+
}));
|
|
7537
|
+
this.standaloneItems.set(entityId, item);
|
|
7538
|
+
}
|
|
7539
|
+
Remove(id) {
|
|
7540
|
+
var _a;
|
|
7541
|
+
const known = this.definitions.delete(id);
|
|
7542
|
+
this.visibility.delete(id);
|
|
7543
|
+
this.errors.delete(id);
|
|
7544
|
+
(_a = this.pending.get(id)) === null || _a === void 0 ? void 0 : _a.abort();
|
|
7545
|
+
this.pending.delete(id);
|
|
7546
|
+
const group = this.active.get(id);
|
|
7547
|
+
if (!group) {
|
|
7548
|
+
// Nothing to unindex. Say so only if there was a definition to forget.
|
|
7549
|
+
if (known) {
|
|
7550
|
+
this.notify();
|
|
7551
|
+
}
|
|
7552
|
+
return;
|
|
7553
|
+
}
|
|
7554
|
+
this.unindex(id);
|
|
7555
|
+
this.active.delete(id);
|
|
7556
|
+
this.refresh(new Set(group.items.keys()));
|
|
7557
|
+
this.notify();
|
|
7558
|
+
}
|
|
7559
|
+
Clear() {
|
|
7560
|
+
for (const controller of this.pending.values()) {
|
|
7561
|
+
controller.abort();
|
|
7562
|
+
}
|
|
7563
|
+
this.pending.clear();
|
|
7564
|
+
const affected = new Set(this.members.keys());
|
|
7565
|
+
this.active.clear();
|
|
7566
|
+
this.members.clear();
|
|
7567
|
+
this.definitions.clear();
|
|
7568
|
+
this.visibility.clear();
|
|
7569
|
+
this.errors.clear();
|
|
7570
|
+
this.refresh(affected);
|
|
7571
|
+
this.notify();
|
|
7572
|
+
}
|
|
7573
|
+
Dispose() {
|
|
7574
|
+
for (const controller of this.pending.values()) {
|
|
7575
|
+
controller.abort();
|
|
7576
|
+
}
|
|
7577
|
+
for (const label of this.standalone.values()) {
|
|
7578
|
+
label.Dispose();
|
|
7579
|
+
}
|
|
7580
|
+
this.pending.clear();
|
|
7581
|
+
this.standalone.clear();
|
|
7582
|
+
this.standaloneItems.clear();
|
|
7583
|
+
this.active.clear();
|
|
7584
|
+
this.members.clear();
|
|
7585
|
+
this.definitions.clear();
|
|
7586
|
+
this.visibility.clear();
|
|
7587
|
+
this.errors.clear();
|
|
7588
|
+
}
|
|
7589
|
+
unindex(groupId) {
|
|
7590
|
+
var _a;
|
|
7591
|
+
for (const id of ((_a = this.active.get(groupId)) === null || _a === void 0 ? void 0 : _a.items.keys()) || []) {
|
|
7592
|
+
const groups = this.members.get(id);
|
|
7593
|
+
groups === null || groups === void 0 ? void 0 : groups.delete(groupId);
|
|
7594
|
+
if (!(groups === null || groups === void 0 ? void 0 : groups.size)) {
|
|
7595
|
+
this.members.delete(id);
|
|
7596
|
+
}
|
|
7597
|
+
}
|
|
7598
|
+
}
|
|
7599
|
+
refresh(ids) {
|
|
7600
|
+
var _a;
|
|
7601
|
+
// Creation drains through the register's bounded update queue, including source-only labels.
|
|
7602
|
+
for (const id of ids) {
|
|
7603
|
+
(_a = this.standalone.get(id)) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
7604
|
+
this.standalone.delete(id);
|
|
7605
|
+
this.standaloneItems.delete(id);
|
|
7606
|
+
}
|
|
7607
|
+
this.register.ForceUpdate({ entityIds: Array.from(ids) });
|
|
7608
|
+
this.register.Viewer.scene.requestRender();
|
|
7609
|
+
}
|
|
7610
|
+
}
|
|
7611
|
+
EntityLabelGroup.Manager = Manager;
|
|
7612
|
+
/*
|
|
7613
|
+
* Rejects invalid geometry settings before they can create unbounded spatial-index work.
|
|
7614
|
+
*/
|
|
7615
|
+
function ValidateOptions(options) {
|
|
7616
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
7617
|
+
if (!options) {
|
|
7618
|
+
return;
|
|
7619
|
+
}
|
|
7620
|
+
if (options.iconBackground != null && typeof options.iconBackground !== "boolean") {
|
|
7621
|
+
throw new Error("Label iconBackground must be a boolean");
|
|
7622
|
+
}
|
|
7623
|
+
for (const value of [options.icon, options.iconUrl, options.iconClass, options.iconColor, options.text]) {
|
|
7624
|
+
if (value != null && typeof value !== "string" && !Array.isArray(value)) {
|
|
7625
|
+
throw new Error("Label icons must be strings or Calculator field arrays");
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7628
|
+
if (options.iconScale != null && !Array.isArray(options.iconScale) && !Number.isFinite(options.iconScale)) {
|
|
7629
|
+
throw new Error("Label iconScale must be finite or a Calculator field array");
|
|
7630
|
+
}
|
|
7631
|
+
if (options.iconPriority != null && !Array.isArray(options.iconPriority) && !Number.isFinite(options.iconPriority)) {
|
|
7632
|
+
throw new Error("Label iconPriority must be finite or a Calculator field array");
|
|
7633
|
+
}
|
|
7634
|
+
for (const value of [options.iconSize, options.leaderLength, options.near, options.far, (_a = options.cluster) === null || _a === void 0 ? void 0 : _a.pixelRange, (_b = options.pointerAvoidance) === null || _b === void 0 ? void 0 : _b.gap, (_c = options.pointerAvoidance) === null || _c === void 0 ? void 0 : _c.delay, (_d = options.pointerAvoidance) === null || _d === void 0 ? void 0 : _d.transitionDuration, (_e = options.anchorRing) === null || _e === void 0 ? void 0 : _e.nearDistance, (_f = options.anchorRing) === null || _f === void 0 ? void 0 : _f.nearRadius, (_g = options.anchorRing) === null || _g === void 0 ? void 0 : _g.hoverDistance, (_h = options.anchorRing) === null || _h === void 0 ? void 0 : _h.hoverRadius, (_j = options.anchorRing) === null || _j === void 0 ? void 0 : _j.transitionDuration]) {
|
|
7635
|
+
if (value != null && (!Number.isFinite(value) || value < 0)) {
|
|
7636
|
+
throw new Error("Label dimensions and distances must be finite and nonnegative");
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
if (((_k = options.near) !== null && _k !== void 0 ? _k : 0) > ((_l = options.far) !== null && _l !== void 0 ? _l : Infinity)) {
|
|
7640
|
+
throw new Error("Label near must not exceed far");
|
|
7641
|
+
}
|
|
7642
|
+
if (options.overlapOpacity != null && (!Number.isFinite(options.overlapOpacity) || options.overlapOpacity < 0 || options.overlapOpacity > 1)) {
|
|
7643
|
+
throw new Error("Label overlapOpacity must be between zero and one");
|
|
7644
|
+
}
|
|
7645
|
+
if (((_m = options.cluster) === null || _m === void 0 ? void 0 : _m.minSize) != null && (!Number.isInteger(options.cluster.minSize) || options.cluster.minSize < 2)) {
|
|
7646
|
+
throw new Error("Label cluster minSize must be an integer of at least two");
|
|
7647
|
+
}
|
|
7648
|
+
}
|
|
7649
|
+
EntityLabelGroup.ValidateOptions = ValidateOptions;
|
|
7650
|
+
})(exports.EntityLabelGroup || (exports.EntityLabelGroup = {}));
|
|
7651
|
+
|
|
5990
7652
|
/**
|
|
5991
7653
|
* Utility for rendering parabolas between two points on the map.
|
|
5992
7654
|
*/
|
|
@@ -7480,7 +9142,7 @@
|
|
|
7480
9142
|
}
|
|
7481
9143
|
}
|
|
7482
9144
|
function updateEntity(viewer, entityId, register, refresh, cache = {}) {
|
|
7483
|
-
var _a;
|
|
9145
|
+
var _a, _b, _c;
|
|
7484
9146
|
if (!entityId) {
|
|
7485
9147
|
// What are we doing?
|
|
7486
9148
|
return;
|
|
@@ -7593,20 +9255,25 @@
|
|
|
7593
9255
|
}
|
|
7594
9256
|
}
|
|
7595
9257
|
}
|
|
7596
|
-
|
|
9258
|
+
const labelGroup = register.GetLabelGroupFor(rego.entityId, rego.menuItemId);
|
|
9259
|
+
if ((state.labelled || labelGroup) && visible) {
|
|
7597
9260
|
exports.EntityLabel.Attach({
|
|
7598
9261
|
rego,
|
|
7599
9262
|
viewer,
|
|
7600
|
-
api: register.ApiGetters.GetBruceApi(),
|
|
7601
|
-
visualRegister: register
|
|
9263
|
+
api: (_b = register.ApiGetters) === null || _b === void 0 ? void 0 : _b.GetBruceApi(),
|
|
9264
|
+
visualRegister: register,
|
|
9265
|
+
options: labelGroup === null || labelGroup === void 0 ? void 0 : labelGroup.options,
|
|
9266
|
+
groupId: labelGroup === null || labelGroup === void 0 ? void 0 : labelGroup.groupId,
|
|
9267
|
+
persistent: true
|
|
7602
9268
|
});
|
|
7603
9269
|
}
|
|
7604
|
-
else {
|
|
9270
|
+
else if (!visible || ((_c = exports.EntityLabel.GetLabel({ rego })) === null || _c === void 0 ? void 0 : _c.Persistent)) {
|
|
7605
9271
|
exports.EntityLabel.Detatch({
|
|
7606
|
-
rego
|
|
9272
|
+
rego, force: true
|
|
7607
9273
|
});
|
|
7608
9274
|
}
|
|
7609
9275
|
}
|
|
9276
|
+
register.RefreshLabelGroupEntity(entityId);
|
|
7610
9277
|
}
|
|
7611
9278
|
function markEntity(register, rego, visual, ignoreParent) {
|
|
7612
9279
|
const vis = visual;
|
|
@@ -7717,6 +9384,7 @@
|
|
|
7717
9384
|
}
|
|
7718
9385
|
return this.onUpdate;
|
|
7719
9386
|
}
|
|
9387
|
+
get OnLabelGroupsChanged() { return this.labelGroupsChanged; }
|
|
7720
9388
|
constructor(params) {
|
|
7721
9389
|
this.id = BModels.ObjectUtils.UId();
|
|
7722
9390
|
this.disposed = false;
|
|
@@ -7755,10 +9423,35 @@
|
|
|
7755
9423
|
this.menuItemSources = new Map();
|
|
7756
9424
|
// Set when the data source order no longer matches the zIndexes seen, so it is re-applied once.
|
|
7757
9425
|
this.sourceOrderDirty = false;
|
|
9426
|
+
this.labelGroupsChanged = new BModels.BruceEvent();
|
|
9427
|
+
this.hoverRingState = {};
|
|
9428
|
+
this.retiringHoverLabels = new Map();
|
|
7758
9429
|
/*
|
|
7759
9430
|
* Tilesets in the scene, keyed by the tileset itself.
|
|
7760
9431
|
*/
|
|
7761
9432
|
this.tilesets = new Map();
|
|
9433
|
+
this.ClearLabelHover = () => {
|
|
9434
|
+
if (!this.labelHover && !this.hoverLabel) {
|
|
9435
|
+
return;
|
|
9436
|
+
}
|
|
9437
|
+
this.ReleaseHoverLabel();
|
|
9438
|
+
this.labelHover = undefined;
|
|
9439
|
+
clearTimeout(this.hoverRingReset);
|
|
9440
|
+
this.hoverRingReset = setTimeout(() => { this.hoverRingState = {}; }, 400);
|
|
9441
|
+
const doc = this.viewer.container.ownerDocument;
|
|
9442
|
+
doc.removeEventListener("pointermove", this.CheckLabelHoverBounds, true);
|
|
9443
|
+
this.viewer.container.removeEventListener("pointerleave", this.CheckLabelHoverBounds);
|
|
9444
|
+
doc.defaultView.removeEventListener("blur", this.ClearLabelHover);
|
|
9445
|
+
if (!this.viewer.isDestroyed()) {
|
|
9446
|
+
this.viewer.scene.requestRender();
|
|
9447
|
+
}
|
|
9448
|
+
};
|
|
9449
|
+
this.CheckLabelHoverBounds = (event) => {
|
|
9450
|
+
const bounds = this.viewer.canvas.getBoundingClientRect();
|
|
9451
|
+
if (event.clientX < bounds.left || event.clientX >= bounds.right || event.clientY < bounds.top || event.clientY >= bounds.bottom) {
|
|
9452
|
+
this.ClearLabelHover();
|
|
9453
|
+
}
|
|
9454
|
+
};
|
|
7762
9455
|
this.viewer = params.viewer;
|
|
7763
9456
|
this.apiGetters = params.apiGetters;
|
|
7764
9457
|
this.cameraCullerDispose = exports.VisualRegisterCuller.Monitor({
|
|
@@ -7954,6 +9647,7 @@
|
|
|
7954
9647
|
const BATCH_SIZE = 300;
|
|
7955
9648
|
if (this.updateQueue.length) {
|
|
7956
9649
|
this.updateQueueInterval = setInterval(() => {
|
|
9650
|
+
var _a;
|
|
7957
9651
|
if (this.Disposed || (!this.viewer || !this.viewer.scene || this.viewer.isDestroyed())) {
|
|
7958
9652
|
clearInterval(this.updateQueueInterval);
|
|
7959
9653
|
this.updateQueueInterval = null;
|
|
@@ -7966,6 +9660,8 @@
|
|
|
7966
9660
|
this.updateQueueIds.delete(entityId);
|
|
7967
9661
|
// Check if still registered.
|
|
7968
9662
|
if (entityId && (!this.rego[entityId] || !this.rego[entityId].length)) {
|
|
9663
|
+
(_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.RefreshEntity(entityId);
|
|
9664
|
+
delete this.updateQueueSettings[entityId];
|
|
7969
9665
|
continue;
|
|
7970
9666
|
}
|
|
7971
9667
|
updateEntity(this.viewer, entityId, this, this.updateQueueSettings[entityId] == null ? false : this.updateQueueSettings[entityId], cache);
|
|
@@ -8623,8 +10319,23 @@
|
|
|
8623
10319
|
markEntity(this, rego, rego.visual, false);
|
|
8624
10320
|
}
|
|
8625
10321
|
Dispose() {
|
|
8626
|
-
var _a, _b, _c, _d;
|
|
8627
|
-
|
|
10322
|
+
var _a, _b, _c, _d, _e;
|
|
10323
|
+
this.ClearLabelHover();
|
|
10324
|
+
clearTimeout(this.hoverRingReset);
|
|
10325
|
+
this.hoverRingState = {};
|
|
10326
|
+
for (const { label, timer } of this.retiringHoverLabels.values()) {
|
|
10327
|
+
clearTimeout(timer);
|
|
10328
|
+
exports.EntityLabel.Detatch({ label });
|
|
10329
|
+
}
|
|
10330
|
+
this.retiringHoverLabels.clear();
|
|
10331
|
+
(_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
10332
|
+
this.labelGroupsChanged.Clear();
|
|
10333
|
+
for (const regos of Object.values(this.rego)) {
|
|
10334
|
+
for (const rego of regos)
|
|
10335
|
+
exports.EntityLabel.Detatch({ rego, force: true });
|
|
10336
|
+
}
|
|
10337
|
+
exports.EntityLabel.SetContainer(this.viewer);
|
|
10338
|
+
(_b = this.cameraCullerDispose) === null || _b === void 0 ? void 0 : _b.call(this, {
|
|
8628
10339
|
uncull: false
|
|
8629
10340
|
});
|
|
8630
10341
|
this.cameraCullerDispose = null;
|
|
@@ -8640,7 +10351,7 @@
|
|
|
8640
10351
|
this.disposed = true;
|
|
8641
10352
|
for (const record of Array.from(this.menuItemSources.values())) {
|
|
8642
10353
|
try {
|
|
8643
|
-
(
|
|
10354
|
+
(_d = (_c = this.viewer) === null || _c === void 0 ? void 0 : _c.dataSources) === null || _d === void 0 ? void 0 : _d.remove(record.source, true);
|
|
8644
10355
|
}
|
|
8645
10356
|
catch (e) {
|
|
8646
10357
|
console.error(e);
|
|
@@ -8649,7 +10360,7 @@
|
|
|
8649
10360
|
this.menuItemSources.clear();
|
|
8650
10361
|
// Hand every tileset's show flag back to its owner, holding whatever the owner last asked for.
|
|
8651
10362
|
for (const rego of Array.from(this.tilesets.values())) {
|
|
8652
|
-
(
|
|
10363
|
+
(_e = rego.gate) === null || _e === void 0 ? void 0 : _e.Release();
|
|
8653
10364
|
}
|
|
8654
10365
|
this.tilesets.clear();
|
|
8655
10366
|
}
|
|
@@ -9601,7 +11312,7 @@
|
|
|
9601
11312
|
* @returns
|
|
9602
11313
|
*/
|
|
9603
11314
|
RemoveRegos(params) {
|
|
9604
|
-
var _a, _b, _c;
|
|
11315
|
+
var _a, _b, _c, _d, _e;
|
|
9605
11316
|
let { entityId, menuItemId, doUpdate, relation, retainTagIds, requestRender, doRemove, source, lazy, onComplete } = params;
|
|
9606
11317
|
if (doUpdate == null || doUpdate === undefined) {
|
|
9607
11318
|
doUpdate = true;
|
|
@@ -9622,7 +11333,7 @@
|
|
|
9622
11333
|
}
|
|
9623
11334
|
}
|
|
9624
11335
|
const removeOne = (entityId) => {
|
|
9625
|
-
var _a, _b;
|
|
11336
|
+
var _a, _b, _c;
|
|
9626
11337
|
const entityRegos = this.rego[entityId];
|
|
9627
11338
|
if (!entityRegos) {
|
|
9628
11339
|
return;
|
|
@@ -9637,7 +11348,7 @@
|
|
|
9637
11348
|
return;
|
|
9638
11349
|
}
|
|
9639
11350
|
exports.EntityLabel.Detatch({
|
|
9640
|
-
rego
|
|
11351
|
+
rego, force: true
|
|
9641
11352
|
});
|
|
9642
11353
|
// Never tear down the graphic the caller is registering: the renderers hand back
|
|
9643
11354
|
// the same object when they reuse it, so removing it here destroys what replaces it.
|
|
@@ -9662,15 +11373,14 @@
|
|
|
9662
11373
|
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.Trigger(update);
|
|
9663
11374
|
}
|
|
9664
11375
|
// Only worth refreshing while the Entity is still drawn by something else, since
|
|
9665
|
-
// losing this rego can change which of the survivors wins.
|
|
9666
|
-
// nothing to restyle, and queueing one per removed Entity is what turns disabling a
|
|
9667
|
-
// large menu item into minutes of scheduled work.
|
|
11376
|
+
// losing this rego can change which of the survivors wins.
|
|
9668
11377
|
if (doesInclude && ((_b = this.rego[entityId]) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
9669
11378
|
this.queueUpdate({
|
|
9670
11379
|
entityId: entityId,
|
|
9671
11380
|
refresh: false
|
|
9672
11381
|
});
|
|
9673
11382
|
}
|
|
11383
|
+
(_c = this.labelGroups) === null || _c === void 0 ? void 0 : _c.RefreshEntity(entityId);
|
|
9674
11384
|
};
|
|
9675
11385
|
const finish = () => {
|
|
9676
11386
|
this.releaseMenuItemCollection(menuItemId);
|
|
@@ -9701,7 +11411,7 @@
|
|
|
9701
11411
|
return;
|
|
9702
11412
|
}
|
|
9703
11413
|
exports.EntityLabel.Detatch({
|
|
9704
|
-
rego
|
|
11414
|
+
rego, force: true
|
|
9705
11415
|
});
|
|
9706
11416
|
// Never tear down the graphic the caller is registering: the renderers hand back
|
|
9707
11417
|
// the same object when they reuse it, so removing it here destroys what replaces it.
|
|
@@ -9720,7 +11430,7 @@
|
|
|
9720
11430
|
if (source !== EUpdateSource.TREE_CASCADE) {
|
|
9721
11431
|
(_b = this.onUpdate) === null || _b === void 0 ? void 0 : _b.Trigger(update);
|
|
9722
11432
|
}
|
|
9723
|
-
this.rego[entityId] =
|
|
11433
|
+
this.rego[entityId] = this.rego[entityId].filter(r => r.menuItemId !== menuItemId);
|
|
9724
11434
|
this.unindexMenuItemEntityIfAbsent(menuItemId, entityId);
|
|
9725
11435
|
if (doUpdate && menuItemId) {
|
|
9726
11436
|
this.queueUpdate({
|
|
@@ -9729,6 +11439,7 @@
|
|
|
9729
11439
|
});
|
|
9730
11440
|
}
|
|
9731
11441
|
}
|
|
11442
|
+
(_c = this.labelGroups) === null || _c === void 0 ? void 0 : _c.RefreshEntity(entityId);
|
|
9732
11443
|
}
|
|
9733
11444
|
else if (relation) {
|
|
9734
11445
|
const relationKey = RelationRenderEngine.GetRenderGroupId(relation);
|
|
@@ -9740,7 +11451,7 @@
|
|
|
9740
11451
|
continue;
|
|
9741
11452
|
}
|
|
9742
11453
|
exports.EntityLabel.Detatch({
|
|
9743
|
-
rego
|
|
11454
|
+
rego, force: true
|
|
9744
11455
|
});
|
|
9745
11456
|
removeEntity(this.viewer, rego.visual);
|
|
9746
11457
|
rego.visual = null;
|
|
@@ -9749,6 +11460,7 @@
|
|
|
9749
11460
|
delete this.rego[entityId];
|
|
9750
11461
|
}
|
|
9751
11462
|
this.unindexMenuItemEntityIfAbsent(rego.menuItemId, entityId);
|
|
11463
|
+
(_d = this.labelGroups) === null || _d === void 0 ? void 0 : _d.RefreshEntity(entityId);
|
|
9752
11464
|
const update = {
|
|
9753
11465
|
type: EVisualUpdateType.Remove,
|
|
9754
11466
|
entityId: rego.entityId,
|
|
@@ -9758,7 +11470,7 @@
|
|
|
9758
11470
|
update.source = source;
|
|
9759
11471
|
}
|
|
9760
11472
|
if (source !== EUpdateSource.TREE_CASCADE) {
|
|
9761
|
-
(
|
|
11473
|
+
(_e = this.onUpdate) === null || _e === void 0 ? void 0 : _e.Trigger(update);
|
|
9762
11474
|
}
|
|
9763
11475
|
if (doUpdate) {
|
|
9764
11476
|
this.queueUpdate({
|
|
@@ -9777,7 +11489,7 @@
|
|
|
9777
11489
|
* @param params
|
|
9778
11490
|
*/
|
|
9779
11491
|
RemoveRegosByVisuals(params) {
|
|
9780
|
-
var _a, _b;
|
|
11492
|
+
var _a, _b, _c;
|
|
9781
11493
|
const { doRemove = true, requestRender = true, source, doUpdate, menuItemId } = params;
|
|
9782
11494
|
const removedEntityIds = new Set();
|
|
9783
11495
|
for (const visual of params.visuals) {
|
|
@@ -9792,9 +11504,8 @@
|
|
|
9792
11504
|
continue;
|
|
9793
11505
|
}
|
|
9794
11506
|
if (rego.visual === visual) {
|
|
9795
|
-
// The primary graphic for this rego - remove the rego entirely.
|
|
9796
11507
|
exports.EntityLabel.Detatch({
|
|
9797
|
-
rego
|
|
11508
|
+
rego, force: true
|
|
9798
11509
|
});
|
|
9799
11510
|
if (doRemove != false) {
|
|
9800
11511
|
removeEntity(this.viewer, rego.visual);
|
|
@@ -9823,9 +11534,10 @@
|
|
|
9823
11534
|
});
|
|
9824
11535
|
}
|
|
9825
11536
|
removedEntityIds.add(entityId);
|
|
11537
|
+
(_b = this.labelGroups) === null || _b === void 0 ? void 0 : _b.RefreshEntity(entityId);
|
|
9826
11538
|
}
|
|
9827
11539
|
else {
|
|
9828
|
-
const siblings = (
|
|
11540
|
+
const siblings = (_c = rego.visual) === null || _c === void 0 ? void 0 : _c["_siblingGraphics"];
|
|
9829
11541
|
if (siblings === null || siblings === void 0 ? void 0 : siblings.length) {
|
|
9830
11542
|
if (doRemove != false && siblings.includes(visual)) {
|
|
9831
11543
|
removeEntity(this.viewer, visual);
|
|
@@ -10092,6 +11804,204 @@
|
|
|
10092
11804
|
}
|
|
10093
11805
|
return map;
|
|
10094
11806
|
}
|
|
11807
|
+
ReleaseHoverLabel(immediate = false) {
|
|
11808
|
+
const label = this.hoverLabel;
|
|
11809
|
+
this.hoverLabel = undefined;
|
|
11810
|
+
if (!label || label.Disposed || label.Persistent) {
|
|
11811
|
+
return;
|
|
11812
|
+
}
|
|
11813
|
+
if (immediate) {
|
|
11814
|
+
exports.EntityLabel.Detatch({ label });
|
|
11815
|
+
return;
|
|
11816
|
+
}
|
|
11817
|
+
label.SetHoverVisible(false);
|
|
11818
|
+
const key = JSON.stringify([label.Rego.entityId, label.Rego.menuItemId || ""]);
|
|
11819
|
+
const previous = this.retiringHoverLabels.get(key);
|
|
11820
|
+
if (previous) {
|
|
11821
|
+
clearTimeout(previous.timer);
|
|
11822
|
+
exports.EntityLabel.Detatch({ label: previous.label });
|
|
11823
|
+
}
|
|
11824
|
+
// Retain briefly beyond the fade to bridge debounced same-target hover updates.
|
|
11825
|
+
const timer = setTimeout(() => {
|
|
11826
|
+
this.retiringHoverLabels.delete(key);
|
|
11827
|
+
exports.EntityLabel.Detatch({ label });
|
|
11828
|
+
}, 240);
|
|
11829
|
+
this.retiringHoverLabels.set(key, { label, timer });
|
|
11830
|
+
}
|
|
11831
|
+
/*
|
|
11832
|
+
* Owns temporary positioning separately from persistent label membership and world anchors.
|
|
11833
|
+
*/
|
|
11834
|
+
SetLabelHover(params) {
|
|
11835
|
+
var _a, _b;
|
|
11836
|
+
if (this.disposed) {
|
|
11837
|
+
return;
|
|
11838
|
+
}
|
|
11839
|
+
if (!(params === null || params === void 0 ? void 0 : params.entityId)) {
|
|
11840
|
+
this.ClearLabelHover();
|
|
11841
|
+
return;
|
|
11842
|
+
}
|
|
11843
|
+
if (params.position && (!Number.isFinite(params.position.x) || !Number.isFinite(params.position.y) ||
|
|
11844
|
+
params.position.x < 0 || params.position.y < 0 ||
|
|
11845
|
+
params.position.x >= this.viewer.canvas.clientWidth || params.position.y >= this.viewer.canvas.clientHeight)) {
|
|
11846
|
+
this.ClearLabelHover();
|
|
11847
|
+
return;
|
|
11848
|
+
}
|
|
11849
|
+
const changed = ((_a = this.labelHover) === null || _a === void 0 ? void 0 : _a.entityId) !== params.entityId || ((_b = this.labelHover) === null || _b === void 0 ? void 0 : _b.menuItemId) !== params.menuItemId;
|
|
11850
|
+
if (changed) {
|
|
11851
|
+
this.ClearLabelHover();
|
|
11852
|
+
}
|
|
11853
|
+
clearTimeout(this.hoverRingReset);
|
|
11854
|
+
this.labelHover = {
|
|
11855
|
+
entityId: params.entityId,
|
|
11856
|
+
menuItemId: params.menuItemId,
|
|
11857
|
+
position: params.position ? { ...params.position } : undefined,
|
|
11858
|
+
createIfMissing: params.createIfMissing !== false
|
|
11859
|
+
};
|
|
11860
|
+
const doc = this.viewer.container.ownerDocument;
|
|
11861
|
+
doc.addEventListener("pointermove", this.CheckLabelHoverBounds, true);
|
|
11862
|
+
this.viewer.container.addEventListener("pointerleave", this.CheckLabelHoverBounds);
|
|
11863
|
+
doc.defaultView.addEventListener("blur", this.ClearLabelHover);
|
|
11864
|
+
this.SyncLabelHover();
|
|
11865
|
+
this.viewer.scene.requestRender();
|
|
11866
|
+
}
|
|
11867
|
+
GetLabelHoverPosition(entityId, menuItemId) {
|
|
11868
|
+
const hover = this.labelHover;
|
|
11869
|
+
return (hover === null || hover === void 0 ? void 0 : hover.entityId) === entityId && (hover.menuItemId == null || hover.menuItemId === menuItemId) ? hover.position : undefined;
|
|
11870
|
+
}
|
|
11871
|
+
SyncLabelHover() {
|
|
11872
|
+
var _a, _b, _c, _d;
|
|
11873
|
+
const hover = this.labelHover;
|
|
11874
|
+
if (!hover || this.disposed) {
|
|
11875
|
+
return;
|
|
11876
|
+
}
|
|
11877
|
+
if ((_a = this.hoverLabel) === null || _a === void 0 ? void 0 : _a.Disposed) {
|
|
11878
|
+
this.hoverLabel = undefined;
|
|
11879
|
+
}
|
|
11880
|
+
if (!hover.createIfMissing) {
|
|
11881
|
+
this.ReleaseHoverLabel(true);
|
|
11882
|
+
return;
|
|
11883
|
+
}
|
|
11884
|
+
const group = this.GetLabelGroupFor(hover.entityId, hover.menuItemId);
|
|
11885
|
+
let rego = this.GetRego(hover);
|
|
11886
|
+
const key = JSON.stringify([hover.entityId, hover.menuItemId || ""]);
|
|
11887
|
+
const retiring = this.retiringHoverLabels.get(key);
|
|
11888
|
+
if (retiring) {
|
|
11889
|
+
clearTimeout(retiring.timer);
|
|
11890
|
+
this.retiringHoverLabels.delete(key);
|
|
11891
|
+
if (!retiring.label.Disposed) {
|
|
11892
|
+
this.hoverLabel = retiring.label;
|
|
11893
|
+
}
|
|
11894
|
+
}
|
|
11895
|
+
const existing = rego && exports.EntityLabel.GetLabel({ rego });
|
|
11896
|
+
const state = this.GetState(hover);
|
|
11897
|
+
if ((!rego && !group) || state.hidden || ((_b = rego === null || rego === void 0 ? void 0 : rego.visual) === null || _b === void 0 ? void 0 : _b.show) === false ||
|
|
11898
|
+
(this.GetIsIsolatedAny() && !state.isolated && this.GetIsolationOpacity() == null) ||
|
|
11899
|
+
(existing && existing !== this.hoverLabel && existing.HasText) ||
|
|
11900
|
+
(group && group.options.presentation !== "icon")) {
|
|
11901
|
+
this.ReleaseHoverLabel(true);
|
|
11902
|
+
return;
|
|
11903
|
+
}
|
|
11904
|
+
if (this.hoverLabel && !this.hoverLabel.Disposed) {
|
|
11905
|
+
this.hoverLabel.SetHoverVisible(true);
|
|
11906
|
+
return;
|
|
11907
|
+
}
|
|
11908
|
+
// Query-only icon groups have coordinates but no registered scene visual to attach to.
|
|
11909
|
+
if (!rego && group && [group.item.longitude, group.item.latitude, (_c = group.item.altitude) !== null && _c !== void 0 ? _c : 0].every(Number.isFinite)) {
|
|
11910
|
+
rego = {
|
|
11911
|
+
entityId: hover.entityId,
|
|
11912
|
+
menuItemId: hover.menuItemId,
|
|
11913
|
+
name: group.options.text,
|
|
11914
|
+
priority: 0,
|
|
11915
|
+
visual: new Cesium.Entity({
|
|
11916
|
+
position: Cesium.Cartesian3.fromDegrees(group.item.longitude, group.item.latitude, group.item.altitude || 0),
|
|
11917
|
+
point: {
|
|
11918
|
+
pixelSize: 0,
|
|
11919
|
+
heightReference: Cesium.HeightReference.NONE
|
|
11920
|
+
}
|
|
11921
|
+
})
|
|
11922
|
+
};
|
|
11923
|
+
}
|
|
11924
|
+
if (!rego) {
|
|
11925
|
+
return;
|
|
11926
|
+
}
|
|
11927
|
+
const params = {
|
|
11928
|
+
rego,
|
|
11929
|
+
viewer: this.viewer,
|
|
11930
|
+
visualRegister: this,
|
|
11931
|
+
api: (_d = this.ApiGetters) === null || _d === void 0 ? void 0 : _d.GetBruceApi(),
|
|
11932
|
+
persistent: false,
|
|
11933
|
+
transient: true,
|
|
11934
|
+
hoverRingState: this.hoverRingState,
|
|
11935
|
+
options: {
|
|
11936
|
+
presentation: "text",
|
|
11937
|
+
text: group === null || group === void 0 ? void 0 : group.options.text,
|
|
11938
|
+
selectOnClick: false
|
|
11939
|
+
},
|
|
11940
|
+
visible: () => {
|
|
11941
|
+
var _a, _b;
|
|
11942
|
+
const current = this.GetState(hover);
|
|
11943
|
+
return (!this.disposed && !current.hidden && ((_a = rego.visual) === null || _a === void 0 ? void 0 : _a.show) !== false &&
|
|
11944
|
+
Boolean(this.GetRego(hover) || ((_b = this.labelGroups) === null || _b === void 0 ? void 0 : _b.Has(hover.entityId, hover.menuItemId))) &&
|
|
11945
|
+
(!this.GetIsIsolatedAny() || current.isolated || this.GetIsolationOpacity() != null));
|
|
11946
|
+
}
|
|
11947
|
+
};
|
|
11948
|
+
this.hoverLabel = existing || group ? new exports.EntityLabel.Label(params) : exports.EntityLabel.Attach(params);
|
|
11949
|
+
}
|
|
11950
|
+
SetLabelContainer(container) {
|
|
11951
|
+
if (this.disposed) {
|
|
11952
|
+
return;
|
|
11953
|
+
}
|
|
11954
|
+
exports.EntityLabel.SetContainer(this.viewer, container);
|
|
11955
|
+
}
|
|
11956
|
+
ClearLabelContainer() {
|
|
11957
|
+
this.SetLabelContainer();
|
|
11958
|
+
}
|
|
11959
|
+
/*
|
|
11960
|
+
* Adds source-driven membership without changing manual labelled state or legacy bookmark snapshots.
|
|
11961
|
+
*/
|
|
11962
|
+
SetLabelGroup(group) {
|
|
11963
|
+
if (this.disposed) {
|
|
11964
|
+
return Promise.reject(new Error("Visual register is disposed"));
|
|
11965
|
+
}
|
|
11966
|
+
if (!this.labelGroups) {
|
|
11967
|
+
this.labelGroups = new exports.EntityLabelGroup.Manager(this, () => this.labelGroupsChanged.Trigger(undefined));
|
|
11968
|
+
}
|
|
11969
|
+
return this.labelGroups.Set(group);
|
|
11970
|
+
}
|
|
11971
|
+
RemoveLabelGroup(id) {
|
|
11972
|
+
var _a;
|
|
11973
|
+
(_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Remove(id);
|
|
11974
|
+
}
|
|
11975
|
+
RefreshLabelGroup(id) {
|
|
11976
|
+
var _a, _b;
|
|
11977
|
+
if (this.disposed) {
|
|
11978
|
+
return Promise.reject(new Error("Visual register is disposed"));
|
|
11979
|
+
}
|
|
11980
|
+
return (_b = (_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Refresh(id)) !== null && _b !== void 0 ? _b : Promise.reject(new Error(`Unknown label group: ${id}`));
|
|
11981
|
+
}
|
|
11982
|
+
SetLabelGroupVisible(id, visible) {
|
|
11983
|
+
var _a, _b;
|
|
11984
|
+
return (_b = (_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.SetVisible(id, visible)) !== null && _b !== void 0 ? _b : false;
|
|
11985
|
+
}
|
|
11986
|
+
ClearLabelGroups() {
|
|
11987
|
+
var _a;
|
|
11988
|
+
(_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Clear();
|
|
11989
|
+
}
|
|
11990
|
+
GetLabelGroups() {
|
|
11991
|
+
var _a;
|
|
11992
|
+
return ((_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Get()) || [];
|
|
11993
|
+
}
|
|
11994
|
+
GetLabelGroupFor(entityId, menuItemId) {
|
|
11995
|
+
var _a;
|
|
11996
|
+
return (_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Resolve(entityId, menuItemId);
|
|
11997
|
+
}
|
|
11998
|
+
RefreshLabelGroupEntity(entityId) {
|
|
11999
|
+
var _a, _b;
|
|
12000
|
+
(_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.RefreshEntity(entityId);
|
|
12001
|
+
if (((_b = this.labelHover) === null || _b === void 0 ? void 0 : _b.entityId) === entityId) {
|
|
12002
|
+
this.SyncLabelHover();
|
|
12003
|
+
}
|
|
12004
|
+
}
|
|
10095
12005
|
}
|
|
10096
12006
|
VisualsRegister.Register = Register;
|
|
10097
12007
|
})(exports.VisualsRegister || (exports.VisualsRegister = {}));
|
|
@@ -10218,6 +12128,8 @@
|
|
|
10218
12128
|
}
|
|
10219
12129
|
class Point {
|
|
10220
12130
|
constructor(lon, lat, id) {
|
|
12131
|
+
this.radius = 0;
|
|
12132
|
+
this.minDistance = 0;
|
|
10221
12133
|
this.lon = lon;
|
|
10222
12134
|
this.lat = lat;
|
|
10223
12135
|
this.id = id;
|
|
@@ -10235,8 +12147,8 @@
|
|
|
10235
12147
|
let xDist = Math.abs(range.x - this.x);
|
|
10236
12148
|
let yDist = Math.abs(range.y - this.y);
|
|
10237
12149
|
let r = this.radius;
|
|
10238
|
-
let w = range.width;
|
|
10239
|
-
let h = range.height;
|
|
12150
|
+
let w = range.width / 2;
|
|
12151
|
+
let h = range.height / 2;
|
|
10240
12152
|
if (xDist > (w + r) || yDist > (h + r)) {
|
|
10241
12153
|
return false;
|
|
10242
12154
|
}
|
|
@@ -10250,8 +12162,7 @@
|
|
|
10250
12162
|
Contains(point) {
|
|
10251
12163
|
const dx = this.x - point.lon;
|
|
10252
12164
|
const dy = this.y - point.lat;
|
|
10253
|
-
|
|
10254
|
-
return distance <= this.radius;
|
|
12165
|
+
return dx * dx + dy * dy <= this.radius * this.radius;
|
|
10255
12166
|
}
|
|
10256
12167
|
}
|
|
10257
12168
|
class Rectangle {
|
|
@@ -10288,13 +12199,13 @@
|
|
|
10288
12199
|
let y = this.boundary.y;
|
|
10289
12200
|
let w = this.boundary.w / 2;
|
|
10290
12201
|
let h = this.boundary.h / 2;
|
|
10291
|
-
let ne = new Rectangle(x + w
|
|
12202
|
+
let ne = new Rectangle(x + w, y - h, w, h);
|
|
10292
12203
|
this.northeast = new Quad(ne, this.capacity);
|
|
10293
|
-
let nw = new Rectangle(x - w
|
|
12204
|
+
let nw = new Rectangle(x - w, y - h, w, h);
|
|
10294
12205
|
this.northwest = new Quad(nw, this.capacity);
|
|
10295
|
-
let se = new Rectangle(x + w
|
|
12206
|
+
let se = new Rectangle(x + w, y + h, w, h);
|
|
10296
12207
|
this.southeast = new Quad(se, this.capacity);
|
|
10297
|
-
let sw = new Rectangle(x - w
|
|
12208
|
+
let sw = new Rectangle(x - w, y + h, w, h);
|
|
10298
12209
|
this.southwest = new Quad(sw, this.capacity);
|
|
10299
12210
|
this.divided = true;
|
|
10300
12211
|
}
|
|
@@ -10302,7 +12213,8 @@
|
|
|
10302
12213
|
if (!this.boundary.Contains(point)) {
|
|
10303
12214
|
return false;
|
|
10304
12215
|
}
|
|
10305
|
-
|
|
12216
|
+
// Coincident points must terminate in a bucket rather than subdividing indefinitely.
|
|
12217
|
+
if (this.points.length < this.capacity || this.boundary.w < 1e-10) {
|
|
10306
12218
|
this.points.push(point);
|
|
10307
12219
|
return true;
|
|
10308
12220
|
}
|
|
@@ -10532,496 +12444,635 @@
|
|
|
10532
12444
|
}
|
|
10533
12445
|
return null;
|
|
10534
12446
|
}
|
|
10535
|
-
const
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
// Queue to force update entities.
|
|
10544
|
-
this.updateEntityQueue = [];
|
|
10545
|
-
this.register = register;
|
|
10546
|
-
this.viewer = register.Viewer;
|
|
10547
|
-
this.menuItemId = menuItemId;
|
|
10548
|
-
let boundary = new Rectangle(0, 0, 360, 180);
|
|
10549
|
-
this.quadTree = new Quad(boundary, 30);
|
|
10550
|
-
this.prevClusteredEntities = new Set();
|
|
10551
|
-
this.currClusteredEntities = new Set();
|
|
10552
|
-
this.clusterEntities = new Map();
|
|
10553
|
-
this.updateQueue = new BModels.DelayQueue(() => {
|
|
10554
|
-
this.doUpdate();
|
|
10555
|
-
}, 1000);
|
|
10556
|
-
this.listenCamera();
|
|
10557
|
-
this.listenSelection();
|
|
10558
|
-
if (settings) {
|
|
10559
|
-
if (!isNaN(+settings.minDistance)) {
|
|
10560
|
-
this.minDistance = +settings.minDistance;
|
|
10561
|
-
}
|
|
10562
|
-
if (!isNaN(+settings.minTotalCount)) {
|
|
10563
|
-
this.minTotalCount = +settings.minTotalCount;
|
|
10564
|
-
}
|
|
10565
|
-
}
|
|
10566
|
-
}
|
|
10567
|
-
Update() {
|
|
10568
|
-
this.updateQueue.Call();
|
|
12447
|
+
const clusterPickers = new WeakMap();
|
|
12448
|
+
/*
|
|
12449
|
+
* One capture listener set per viewer prevents host canvas picking from undoing cluster selection.
|
|
12450
|
+
*/
|
|
12451
|
+
function getClusterPicker(viewer) {
|
|
12452
|
+
let picker = clusterPickers.get(viewer);
|
|
12453
|
+
if (picker) {
|
|
12454
|
+
return picker;
|
|
10569
12455
|
}
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
12456
|
+
const canvas = viewer.canvas;
|
|
12457
|
+
picker = {
|
|
12458
|
+
owners: new Set(),
|
|
12459
|
+
targets: new Map(),
|
|
12460
|
+
remove: () => { }
|
|
12461
|
+
};
|
|
12462
|
+
let gesture;
|
|
12463
|
+
let released;
|
|
12464
|
+
const handler = (event) => {
|
|
12465
|
+
if (viewer.isDestroyed())
|
|
12466
|
+
return;
|
|
12467
|
+
const stop = () => { event.preventDefault(); event.stopImmediatePropagation(); };
|
|
12468
|
+
if (event.type === "pointermove") {
|
|
12469
|
+
if (gesture && Math.hypot(event.clientX - gesture.x, event.clientY - gesture.y) > 6) {
|
|
12470
|
+
gesture.moved = true;
|
|
10574
12471
|
}
|
|
10575
|
-
|
|
12472
|
+
return;
|
|
10576
12473
|
}
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
12474
|
+
if (event.type === "pointercancel") {
|
|
12475
|
+
if (gesture) {
|
|
12476
|
+
released = { ...gesture, moved: true };
|
|
12477
|
+
gesture = null;
|
|
12478
|
+
if (released.target) {
|
|
12479
|
+
stop();
|
|
12480
|
+
}
|
|
12481
|
+
}
|
|
10581
12482
|
return;
|
|
10582
12483
|
}
|
|
10583
|
-
if (
|
|
12484
|
+
if (event.button !== 0) {
|
|
10584
12485
|
return;
|
|
10585
12486
|
}
|
|
10586
|
-
|
|
10587
|
-
if
|
|
10588
|
-
|
|
10589
|
-
this.queueInterval = null;
|
|
12487
|
+
if (event.type === "pointerup" || event.type === "mouseup") {
|
|
12488
|
+
// Only consume releases whose press we owned, even if the cursor left the billboard.
|
|
12489
|
+
if (!gesture) {
|
|
10590
12490
|
return;
|
|
10591
12491
|
}
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
clearInterval(this.queueInterval);
|
|
10598
|
-
this.queueInterval = null;
|
|
12492
|
+
gesture.moved || (gesture.moved = Math.hypot(event.clientX - gesture.x, event.clientY - gesture.y) > 6);
|
|
12493
|
+
released = gesture;
|
|
12494
|
+
gesture = null;
|
|
12495
|
+
if (released.target) {
|
|
12496
|
+
stop();
|
|
10599
12497
|
}
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
var _a;
|
|
10611
|
-
const cameraPos = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic;
|
|
10612
|
-
if (!cameraPos) {
|
|
10613
|
-
return false;
|
|
12498
|
+
return;
|
|
12499
|
+
}
|
|
12500
|
+
const rect = canvas.getBoundingClientRect();
|
|
12501
|
+
const picked = viewer.scene.pick(new Cesium.Cartesian2(event.clientX - rect.left, event.clientY - rect.top));
|
|
12502
|
+
const select = picker.targets.get(picked === null || picked === void 0 ? void 0 : picked.id);
|
|
12503
|
+
if (event.type === "pointerdown" || event.type === "mousedown") {
|
|
12504
|
+
released = null;
|
|
12505
|
+
gesture = { target: select ? picked.id : null, x: event.clientX, y: event.clientY, moved: false };
|
|
12506
|
+
if (gesture.target) {
|
|
12507
|
+
stop();
|
|
10614
12508
|
}
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
12509
|
+
return;
|
|
12510
|
+
}
|
|
12511
|
+
if (released) {
|
|
12512
|
+
const owned = !!released.target;
|
|
12513
|
+
const invalid = released.moved || released.target !== (picked === null || picked === void 0 ? void 0 : picked.id);
|
|
12514
|
+
released = null;
|
|
12515
|
+
if (!owned) {
|
|
12516
|
+
return;
|
|
10619
12517
|
}
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
return distance > 50;
|
|
10624
|
-
};
|
|
10625
|
-
this.listenCameraRemoval = viewer.scene.camera.changed.addEventListener(() => {
|
|
10626
|
-
if (hasMoved()) {
|
|
10627
|
-
this.updateQueue.Call();
|
|
12518
|
+
if (invalid) {
|
|
12519
|
+
stop();
|
|
12520
|
+
return;
|
|
10628
12521
|
}
|
|
10629
|
-
});
|
|
10630
|
-
}
|
|
10631
|
-
/**
|
|
10632
|
-
* Stops listening to camera changes.
|
|
10633
|
-
*/
|
|
10634
|
-
unlistenCamera() {
|
|
10635
|
-
if (this.listenCameraRemoval) {
|
|
10636
|
-
this.listenCameraRemoval();
|
|
10637
|
-
this.listenCameraRemoval = null;
|
|
10638
12522
|
}
|
|
12523
|
+
if (!select) {
|
|
12524
|
+
return;
|
|
12525
|
+
}
|
|
12526
|
+
stop();
|
|
12527
|
+
if (event.type === "click") {
|
|
12528
|
+
select();
|
|
12529
|
+
}
|
|
12530
|
+
};
|
|
12531
|
+
const types = ["pointerdown", "pointermove", "pointerup", "pointercancel", "mousedown", "mouseup", "click", "dblclick"];
|
|
12532
|
+
if (canvas === null || canvas === void 0 ? void 0 : canvas.addEventListener) {
|
|
12533
|
+
for (const type of types) {
|
|
12534
|
+
canvas.addEventListener(type, handler, true);
|
|
12535
|
+
}
|
|
12536
|
+
picker.remove = () => {
|
|
12537
|
+
for (const type of types) {
|
|
12538
|
+
canvas.removeEventListener(type, handler, true);
|
|
12539
|
+
}
|
|
12540
|
+
};
|
|
10639
12541
|
}
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
12542
|
+
clusterPickers.set(viewer, picker);
|
|
12543
|
+
return picker;
|
|
12544
|
+
}
|
|
12545
|
+
/*
|
|
12546
|
+
* Count tiers are bounded so large clusters do not cover the scene with enormous billboards.
|
|
12547
|
+
*/
|
|
12548
|
+
function PointClusterSize(count) {
|
|
12549
|
+
return count >= 10000 ? 140 : count >= 1000 ? 120 : count >= 100 ? 90 : count >= 10 ? 80 : 70;
|
|
12550
|
+
}
|
|
12551
|
+
class PointClustering {
|
|
12552
|
+
constructor(register, menuItemId, settings = {}) {
|
|
12553
|
+
this.register = register;
|
|
12554
|
+
this.menuItemId = menuItemId;
|
|
12555
|
+
this.settings = settings;
|
|
12556
|
+
this.minDistance = 5000;
|
|
12557
|
+
this.minTotalCount = 0;
|
|
12558
|
+
this.currClusteredEntities = new Set();
|
|
12559
|
+
this.clusterEntities = new Map();
|
|
12560
|
+
this.clusterViews = new Map();
|
|
12561
|
+
this.registeredEntityIds = new Set();
|
|
12562
|
+
this.records = new Map();
|
|
12563
|
+
this.disposed = false;
|
|
12564
|
+
this.removals = [];
|
|
12565
|
+
this.selectionQueued = false;
|
|
12566
|
+
this.viewer = register.Viewer;
|
|
12567
|
+
this.settings = settings = settings || {};
|
|
12568
|
+
if (Number.isFinite(+settings.minDistance)) {
|
|
12569
|
+
this.minDistance = Math.max(0, +settings.minDistance);
|
|
12570
|
+
}
|
|
12571
|
+
if (Number.isFinite(+settings.minTotalCount)) {
|
|
12572
|
+
this.minTotalCount = Math.max(0, +settings.minTotalCount);
|
|
12573
|
+
}
|
|
12574
|
+
this.quadTree = new Quad(new Rectangle(0, 0, 360, 180), 30);
|
|
12575
|
+
this.updateQueue = new BModels.DelayQueue(() => this.doUpdate(), 1000);
|
|
12576
|
+
this.picker = getClusterPicker(this.viewer);
|
|
12577
|
+
this.picker.owners.add(this);
|
|
12578
|
+
this.removals.push(this.viewer.scene.camera.changed.addEventListener(() => this.Update()));
|
|
12579
|
+
this.removals.push(this.viewer.scene.terrainProviderChanged.addEventListener(() => this.Update()));
|
|
12580
|
+
this.removals.push(register.OnUpdate.Subscribe(data => {
|
|
12581
|
+
if (data.type === exports.VisualsRegister.EVisualUpdateType.DeselectAll ||
|
|
12582
|
+
(data.entityId && this.registeredEntityIds.has(data.entityId) && data.selected != null)) {
|
|
12583
|
+
if (!this.selectionQueued) {
|
|
12584
|
+
this.selectionQueued = true;
|
|
12585
|
+
Promise.resolve().then(() => {
|
|
12586
|
+
this.selectionQueued = false;
|
|
12587
|
+
if (!this.disposed)
|
|
12588
|
+
this.refreshSelection();
|
|
12589
|
+
});
|
|
12590
|
+
}
|
|
10648
12591
|
}
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
data.type == exports.VisualsRegister.EVisualUpdateType.Update &&
|
|
10652
|
-
this.registeredEntityIds.has(data.entityId)) {
|
|
10653
|
-
this.updateQueue.Call();
|
|
12592
|
+
if ("isolated" in data || (data.entityId && this.registeredEntityIds.has(data.entityId) && "hidden" in data)) {
|
|
12593
|
+
this.Update();
|
|
10654
12594
|
}
|
|
10655
|
-
});
|
|
12595
|
+
}));
|
|
10656
12596
|
}
|
|
10657
|
-
|
|
10658
|
-
if (this.
|
|
10659
|
-
this.
|
|
10660
|
-
this.listenUpdateRemoval = null;
|
|
12597
|
+
Update() {
|
|
12598
|
+
if (!this.disposed) {
|
|
12599
|
+
this.updateQueue.Call();
|
|
10661
12600
|
}
|
|
10662
12601
|
}
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
*/
|
|
12602
|
+
GetClusters() {
|
|
12603
|
+
return Array.from(this.clusterViews.values(), view => ({ ...view, entityIds: [...view.entityIds] }));
|
|
12604
|
+
}
|
|
10667
12605
|
Dispose() {
|
|
10668
12606
|
if (this.disposed) {
|
|
10669
12607
|
return;
|
|
10670
12608
|
}
|
|
10671
|
-
for (let [, entity] of Array.from(this.clusterEntities)) {
|
|
10672
|
-
this.viewer.entities.remove(entity);
|
|
10673
|
-
}
|
|
10674
|
-
this.clusterEntities.clear();
|
|
10675
|
-
this.unlistenCamera();
|
|
10676
|
-
this.unlistenSelection();
|
|
10677
12609
|
this.disposed = true;
|
|
10678
|
-
this.
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
12610
|
+
this.updateQueue.Dispose();
|
|
12611
|
+
for (const remove of this.removals) {
|
|
12612
|
+
remove();
|
|
12613
|
+
}
|
|
12614
|
+
for (const id of this.clusterEntities.keys()) {
|
|
12615
|
+
this.removeClusterEntity(id);
|
|
12616
|
+
}
|
|
12617
|
+
this.picker.owners.delete(this);
|
|
12618
|
+
if (!this.picker.owners.size) {
|
|
12619
|
+
this.picker.remove();
|
|
12620
|
+
clusterPickers.delete(this.viewer);
|
|
12621
|
+
}
|
|
12622
|
+
const restore = [];
|
|
12623
|
+
for (const id of this.registeredEntityIds) {
|
|
12624
|
+
const rego = this.register.GetRego({ entityId: id, menuItemId: this.menuItemId });
|
|
12625
|
+
if ((rego === null || rego === void 0 ? void 0 : rego.overrideShow) === false) {
|
|
10687
12626
|
rego.overrideShow = null;
|
|
10688
|
-
|
|
12627
|
+
restore.push(id);
|
|
10689
12628
|
}
|
|
10690
12629
|
}
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
12630
|
+
this.records.clear();
|
|
12631
|
+
this.registeredEntityIds.clear();
|
|
12632
|
+
this.currClusteredEntities.clear();
|
|
12633
|
+
if (restore.length) {
|
|
12634
|
+
this.register.ForceUpdate({ entityIds: restore });
|
|
10695
12635
|
}
|
|
10696
12636
|
}
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
latSum += point.lat;
|
|
12637
|
+
refreshSelection() {
|
|
12638
|
+
for (const view of this.clusterViews.values()) {
|
|
12639
|
+
const selected = view.entityIds.length > 0 && view.entityIds.every(entityId => this.register.GetIsSelected({ entityId, menuItemId: this.menuItemId }));
|
|
12640
|
+
if (selected === view.selected)
|
|
12641
|
+
continue;
|
|
12642
|
+
view.selected = selected;
|
|
12643
|
+
if (selected)
|
|
12644
|
+
exports.CesiumEntityStyler.Select({ viewer: this.viewer, entity: view.entity, requestRender: false });
|
|
12645
|
+
else
|
|
12646
|
+
exports.CesiumEntityStyler.Deselect({ viewer: this.viewer, entity: view.entity, requestRender: false });
|
|
10708
12647
|
}
|
|
10709
|
-
|
|
10710
|
-
const latAvg = latSum / points.length;
|
|
10711
|
-
return new Point(lonAvg, latAvg, "");
|
|
12648
|
+
this.viewer.scene.requestRender();
|
|
10712
12649
|
}
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
*/
|
|
10717
|
-
doUpdate() {
|
|
10718
|
-
if (this.disposed) {
|
|
12650
|
+
selectCluster(clusterId) {
|
|
12651
|
+
const view = this.clusterViews.get(clusterId);
|
|
12652
|
+
if (this.disposed || !view)
|
|
10719
12653
|
return;
|
|
12654
|
+
this.register.ClearSelected({ requestRender: false });
|
|
12655
|
+
this.register.SetSelected({ entityIds: view.entityIds, selected: true });
|
|
12656
|
+
this.refreshSelection();
|
|
12657
|
+
}
|
|
12658
|
+
resolveGeometry(visual, seen = new Set()) {
|
|
12659
|
+
var _a, _b, _c;
|
|
12660
|
+
if (!visual || seen.has(visual)) {
|
|
12661
|
+
return null;
|
|
10720
12662
|
}
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
const
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
12663
|
+
seen.add(visual);
|
|
12664
|
+
const value = (property) => GetValue(this.viewer, property);
|
|
12665
|
+
const valid = (p) => p && [p.x, p.y, p.z].every(Number.isFinite) && Cesium.Cartesian3.magnitudeSquared(p) > 0;
|
|
12666
|
+
const kind = visual.model || visual.box || visual.cylinder || visual.ellipsoid ? "model" :
|
|
12667
|
+
visual.polygon || visual.rectangle || visual.ellipse ? "polygon" :
|
|
12668
|
+
visual.polyline || visual.corridor || visual.wall || visual.polylineVolume ? "polyline" :
|
|
12669
|
+
visual.point || visual.billboard || visual.label ? "point" : "other";
|
|
12670
|
+
const configured = (_a = this.settings.minDistanceByType) === null || _a === void 0 ? void 0 : _a[kind];
|
|
12671
|
+
let minDistance = Number.isFinite(configured) ? Math.max(0, configured) : this.minDistance * (kind === "point" || kind === "other" ? 1 : 2);
|
|
12672
|
+
const graphic = (visual.model || visual.polygon || visual.rectangle || visual.ellipse || visual.polyline ||
|
|
12673
|
+
visual.corridor || visual.wall || visual.polylineVolume || visual.billboard || visual.point || visual.label || visual.box || visual.cylinder || visual.ellipsoid);
|
|
12674
|
+
let heightRef = (_b = value(graphic === null || graphic === void 0 ? void 0 : graphic.heightReference)) !== null && _b !== void 0 ? _b : Cesium.HeightReference.NONE;
|
|
12675
|
+
if (visual.polyline) {
|
|
12676
|
+
heightRef = value(visual.polyline.clampToGround) ? Cesium.HeightReference.CLAMP_TO_GROUND : Cesium.HeightReference.NONE;
|
|
12677
|
+
}
|
|
12678
|
+
let positions;
|
|
12679
|
+
let height;
|
|
12680
|
+
if (visual.polygon) {
|
|
12681
|
+
const hierarchy = value(visual.polygon.hierarchy);
|
|
12682
|
+
positions = hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.positions;
|
|
12683
|
+
if (!value(visual.polygon.perPositionHeight)) {
|
|
12684
|
+
height = value(visual.polygon.height);
|
|
12685
|
+
if (height == null && value(visual.polygon.extrudedHeight) == null) {
|
|
12686
|
+
heightRef = Cesium.HeightReference.CLAMP_TO_GROUND;
|
|
12687
|
+
}
|
|
12688
|
+
height !== null && height !== void 0 ? height : (height = 0);
|
|
12689
|
+
}
|
|
12690
|
+
}
|
|
12691
|
+
else if (visual.rectangle) {
|
|
12692
|
+
const rectangle = value(visual.rectangle.coordinates);
|
|
12693
|
+
if (rectangle) {
|
|
12694
|
+
positions = [Cesium.Rectangle.northwest(rectangle), Cesium.Rectangle.northeast(rectangle),
|
|
12695
|
+
Cesium.Rectangle.southwest(rectangle), Cesium.Rectangle.southeast(rectangle)].map(c => Cesium.Cartographic.toCartesian(c));
|
|
12696
|
+
}
|
|
12697
|
+
height = value(visual.rectangle.height);
|
|
12698
|
+
if (height == null && value(visual.rectangle.extrudedHeight) == null) {
|
|
12699
|
+
heightRef = Cesium.HeightReference.CLAMP_TO_GROUND;
|
|
12700
|
+
}
|
|
12701
|
+
height !== null && height !== void 0 ? height : (height = 0);
|
|
12702
|
+
}
|
|
12703
|
+
else if (visual.polyline || visual.corridor || visual.wall || visual.polylineVolume) {
|
|
12704
|
+
positions = value(graphic.positions);
|
|
12705
|
+
if (visual.wall && positions) {
|
|
12706
|
+
const minimum = value(visual.wall.minimumHeights);
|
|
12707
|
+
const maximum = value(visual.wall.maximumHeights);
|
|
12708
|
+
positions = positions.flatMap((position, index) => {
|
|
12709
|
+
var _a, _b;
|
|
12710
|
+
if (!valid(position)) {
|
|
12711
|
+
return [];
|
|
12712
|
+
}
|
|
12713
|
+
const carto = Cesium.Cartographic.fromCartesian(position);
|
|
12714
|
+
if (!carto) {
|
|
12715
|
+
return [];
|
|
12716
|
+
}
|
|
12717
|
+
return ([(_a = minimum === null || minimum === void 0 ? void 0 : minimum[index]) !== null && _a !== void 0 ? _a : 0, (_b = maximum === null || maximum === void 0 ? void 0 : maximum[index]) !== null && _b !== void 0 ? _b : carto.height]
|
|
12718
|
+
.filter(Number.isFinite).map(height => Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, height)));
|
|
12719
|
+
});
|
|
12720
|
+
}
|
|
10731
12721
|
}
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
12722
|
+
if (visual.corridor || visual.ellipse) {
|
|
12723
|
+
height = value(graphic.height);
|
|
12724
|
+
if (height == null && value(graphic.extrudedHeight) == null)
|
|
12725
|
+
heightRef = Cesium.HeightReference.CLAMP_TO_GROUND;
|
|
12726
|
+
height !== null && height !== void 0 ? height : (height = 0);
|
|
12727
|
+
}
|
|
12728
|
+
if (!(positions === null || positions === void 0 ? void 0 : positions.length)) {
|
|
12729
|
+
const position = value(visual.position);
|
|
12730
|
+
if (valid(position)) {
|
|
12731
|
+
positions = [position];
|
|
12732
|
+
}
|
|
12733
|
+
}
|
|
12734
|
+
const children = visual._siblingGraphics || [];
|
|
12735
|
+
// Container entities often copy their first child's position; don't count that anchor twice.
|
|
12736
|
+
if (!graphic && children.length) {
|
|
12737
|
+
positions = [];
|
|
12738
|
+
minDistance = 0;
|
|
12739
|
+
}
|
|
12740
|
+
const resolved = [];
|
|
12741
|
+
for (const position of positions || []) {
|
|
12742
|
+
if (!valid(position))
|
|
12743
|
+
continue;
|
|
12744
|
+
let source = position;
|
|
12745
|
+
if (height != null) {
|
|
12746
|
+
const carto = Cesium.Cartographic.fromCartesian(position);
|
|
12747
|
+
if (!carto)
|
|
12748
|
+
continue;
|
|
12749
|
+
source = Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, height);
|
|
12750
|
+
}
|
|
12751
|
+
const actual = exports.DrawingUtils.EnsurePosHeight({
|
|
12752
|
+
viewer: this.viewer,
|
|
12753
|
+
pos3d: source,
|
|
12754
|
+
desiredHeightRef: Cesium.HeightReference.NONE,
|
|
12755
|
+
heightRef
|
|
12756
|
+
});
|
|
12757
|
+
if (valid(actual)) {
|
|
12758
|
+
resolved.push(actual);
|
|
12759
|
+
}
|
|
12760
|
+
}
|
|
12761
|
+
const extrudedHeight = value(graphic === null || graphic === void 0 ? void 0 : graphic.extrudedHeight);
|
|
12762
|
+
if (Number.isFinite(extrudedHeight)) {
|
|
12763
|
+
const reference = (_c = value(graphic.extrudedHeightReference)) !== null && _c !== void 0 ? _c : Cesium.HeightReference.NONE;
|
|
12764
|
+
for (const position of positions || []) {
|
|
12765
|
+
if (!valid(position)) {
|
|
12766
|
+
continue;
|
|
12767
|
+
}
|
|
12768
|
+
const carto = Cesium.Cartographic.fromCartesian(position);
|
|
12769
|
+
if (!carto) {
|
|
12770
|
+
continue;
|
|
12771
|
+
}
|
|
12772
|
+
const actual = exports.DrawingUtils.EnsurePosHeight({
|
|
12773
|
+
viewer: this.viewer,
|
|
12774
|
+
pos3d: Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, extrudedHeight),
|
|
12775
|
+
desiredHeightRef: Cesium.HeightReference.NONE, heightRef: reference
|
|
10739
12776
|
});
|
|
10740
|
-
if (
|
|
10741
|
-
|
|
10742
|
-
entitiesToUpdate.push(id);
|
|
12777
|
+
if (valid(actual)) {
|
|
12778
|
+
resolved.push(actual);
|
|
10743
12779
|
}
|
|
10744
12780
|
}
|
|
10745
12781
|
}
|
|
10746
|
-
const
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
//
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
12782
|
+
const spheres = [];
|
|
12783
|
+
const anchors = [];
|
|
12784
|
+
if (resolved.length) {
|
|
12785
|
+
const sphere = Cesium.BoundingSphere.fromPoints(resolved);
|
|
12786
|
+
// A chord midpoint can lie underground. Preserve the average rendered vertex altitude.
|
|
12787
|
+
const center = Cesium.Cartographic.fromCartesian(sphere.center);
|
|
12788
|
+
if (center) {
|
|
12789
|
+
const altitude = resolved.reduce((sum, p) => sum + Cesium.Cartographic.fromCartesian(p).height, 0) / resolved.length;
|
|
12790
|
+
const position = Cesium.Cartesian3.fromRadians(center.longitude, center.latitude, altitude);
|
|
12791
|
+
sphere.radius += Cesium.Cartesian3.distance(position, sphere.center);
|
|
12792
|
+
sphere.center = position;
|
|
12793
|
+
}
|
|
12794
|
+
if (visual.ellipse) {
|
|
12795
|
+
sphere.radius = Math.max(sphere.radius, value(visual.ellipse.semiMajorAxis) || 0, value(visual.ellipse.semiMinorAxis) || 0);
|
|
12796
|
+
}
|
|
12797
|
+
if (visual.box) {
|
|
12798
|
+
sphere.radius = Math.max(sphere.radius, Cesium.Cartesian3.magnitude(value(visual.box.dimensions) || Cesium.Cartesian3.ZERO) / 2);
|
|
12799
|
+
}
|
|
12800
|
+
if (visual.ellipsoid) {
|
|
12801
|
+
sphere.radius = Math.max(sphere.radius, Cesium.Cartesian3.maximumComponent(value(visual.ellipsoid.radii) || Cesium.Cartesian3.ZERO));
|
|
12802
|
+
}
|
|
12803
|
+
if (visual.cylinder) {
|
|
12804
|
+
sphere.radius = Math.max(sphere.radius, Math.hypot((value(visual.cylinder.length) || 0) / 2, Math.max(value(visual.cylinder.topRadius) || 0, value(visual.cylinder.bottomRadius) || 0)));
|
|
10755
12805
|
}
|
|
10756
|
-
if (
|
|
10757
|
-
|
|
12806
|
+
if (visual.corridor) {
|
|
12807
|
+
sphere.radius += (value(visual.corridor.width) || 0) / 2;
|
|
10758
12808
|
}
|
|
10759
|
-
if (
|
|
10760
|
-
|
|
12809
|
+
if (visual.polylineVolume) {
|
|
12810
|
+
const shape = value(visual.polylineVolume.shape) || [];
|
|
12811
|
+
sphere.radius += shape.reduce((radius, p) => Math.max(radius, Math.hypot(p.x, p.y)), 0);
|
|
10761
12812
|
}
|
|
10762
|
-
|
|
10763
|
-
|
|
12813
|
+
spheres.push(sphere);
|
|
12814
|
+
anchors.push(sphere.center);
|
|
12815
|
+
}
|
|
12816
|
+
for (const child of children) {
|
|
12817
|
+
const result = this.resolveGeometry(child, seen);
|
|
12818
|
+
if (!result) {
|
|
12819
|
+
continue;
|
|
12820
|
+
}
|
|
12821
|
+
spheres.push(new Cesium.BoundingSphere(result.position, result.radius));
|
|
12822
|
+
anchors.push(result.position);
|
|
12823
|
+
minDistance = Math.max(minDistance, result.minDistance);
|
|
12824
|
+
}
|
|
12825
|
+
if (!spheres.length) {
|
|
12826
|
+
return null;
|
|
12827
|
+
}
|
|
12828
|
+
const sphere = spheres.length === 1 ? spheres[0] : Cesium.BoundingSphere.fromBoundingSpheres(spheres);
|
|
12829
|
+
if (!valid(sphere.center) || !Number.isFinite(sphere.radius)) {
|
|
12830
|
+
return null;
|
|
12831
|
+
}
|
|
12832
|
+
if (spheres.length > 1) {
|
|
12833
|
+
const carto = Cesium.Cartographic.fromCartesian(sphere.center);
|
|
12834
|
+
if (!carto) {
|
|
12835
|
+
return null;
|
|
10764
12836
|
}
|
|
10765
|
-
|
|
12837
|
+
const height = anchors.reduce((sum, p) => sum + Cesium.Cartographic.fromCartesian(p).height, 0) / anchors.length;
|
|
12838
|
+
const position = Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, height);
|
|
12839
|
+
sphere.radius += Cesium.Cartesian3.distance(position, sphere.center);
|
|
12840
|
+
sphere.center = position;
|
|
12841
|
+
}
|
|
12842
|
+
return { position: sphere.center, radius: sphere.radius, minDistance };
|
|
12843
|
+
}
|
|
12844
|
+
appearance(id) {
|
|
12845
|
+
var _a, _b, _c, _d, _e, _f;
|
|
12846
|
+
const { visual, metadata } = this.records.get(id);
|
|
12847
|
+
const data = metadata.entity || { Bruce: { ID: id } };
|
|
12848
|
+
let priority;
|
|
12849
|
+
let status;
|
|
12850
|
+
try {
|
|
12851
|
+
priority = Array.isArray(this.settings.iconPriority) ? BModels.Calculator.GetNumber(this.settings.iconPriority, data) : this.settings.iconPriority;
|
|
12852
|
+
status = Array.isArray(this.settings.iconStatus) ? BModels.Calculator.GetString(this.settings.iconStatus, data) : this.settings.iconStatus;
|
|
12853
|
+
}
|
|
12854
|
+
catch {
|
|
12855
|
+
priority = undefined;
|
|
12856
|
+
status = undefined;
|
|
12857
|
+
}
|
|
12858
|
+
const rawImage = GetValue(this.viewer, (_a = visual.billboard) === null || _a === void 0 ? void 0 : _a.image);
|
|
12859
|
+
const imageKey = (_b = visual.billboard) === null || _b === void 0 ? void 0 : _b._billboardImgKey;
|
|
12860
|
+
const iconUrl = (_c = metadata.iconUrl) !== null && _c !== void 0 ? _c : (typeof rawImage === "string" ? rawImage : undefined);
|
|
12861
|
+
// Original URLs retain status tokens after the point renderer converts an image into a data URI.
|
|
12862
|
+
const inferenceUrl = (_e = (_d = metadata.iconUrl) !== null && _d !== void 0 ? _d : imageKey) !== null && _e !== void 0 ? _e : iconUrl;
|
|
12863
|
+
const colorGraphic = visual.point || visual.polygon || visual.polyline || visual.corridor || visual.ellipse || visual.model;
|
|
12864
|
+
const color = colorGraphic ? exports.CesiumEntityStyler.GetDefaultColor(this.viewer, colorGraphic) : null;
|
|
12865
|
+
let colorStatus;
|
|
12866
|
+
if (color && color.alpha > 0 && color.red > 0.5 && color.blue < 0.4) {
|
|
12867
|
+
colorStatus = color.green > 0.4 ? "warning" : "red";
|
|
12868
|
+
}
|
|
12869
|
+
const bgColor = color === null || color === void 0 ? void 0 : color.toCssColorString();
|
|
12870
|
+
return {
|
|
12871
|
+
priority: GetClusterIconPriority({
|
|
12872
|
+
iconPriority: Number.isFinite(priority) ? priority : metadata.iconPriority,
|
|
12873
|
+
iconStatus: (_f = status !== null && status !== void 0 ? status : metadata.iconStatus) !== null && _f !== void 0 ? _f : colorStatus, icon: metadata.icon, iconUrl: inferenceUrl
|
|
12874
|
+
}),
|
|
12875
|
+
iconUrl, bgColor,
|
|
12876
|
+
txtColor: color && color.red * 0.299 + color.green * 0.587 + color.blue * 0.114 > 0.5 ? "black" : "white"
|
|
10766
12877
|
};
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
12878
|
+
}
|
|
12879
|
+
doUpdate() {
|
|
12880
|
+
var _a;
|
|
12881
|
+
if (this.disposed) {
|
|
12882
|
+
return;
|
|
12883
|
+
}
|
|
12884
|
+
const previous = new Set(this.currClusteredEntities);
|
|
12885
|
+
const { clusters } = this.getClusters();
|
|
12886
|
+
const live = new Set(clusters.map(cluster => cluster.center.id));
|
|
12887
|
+
for (const id of this.clusterEntities.keys()) {
|
|
12888
|
+
if (!live.has(id)) {
|
|
12889
|
+
this.removeClusterEntity(id);
|
|
12890
|
+
}
|
|
12891
|
+
}
|
|
12892
|
+
const changed = new Set();
|
|
12893
|
+
for (const id of new Set([...previous, ...this.registeredEntityIds])) {
|
|
12894
|
+
if (this.currClusteredEntities.has(id)) {
|
|
12895
|
+
continue;
|
|
12896
|
+
}
|
|
12897
|
+
const rego = this.register.GetRego({ entityId: id, menuItemId: this.menuItemId });
|
|
12898
|
+
if ((rego === null || rego === void 0 ? void 0 : rego.overrideShow) === false) {
|
|
12899
|
+
rego.overrideShow = null;
|
|
12900
|
+
changed.add(id);
|
|
12901
|
+
}
|
|
12902
|
+
}
|
|
12903
|
+
for (const cluster of clusters) {
|
|
12904
|
+
const clusterId = cluster.center.id;
|
|
12905
|
+
let representative = cluster.center;
|
|
12906
|
+
let appearance = this.appearance(representative.id);
|
|
12907
|
+
if (this.settings.representative !== "nearest") {
|
|
12908
|
+
for (const point of cluster.points) {
|
|
12909
|
+
const candidate = this.appearance(point.id);
|
|
12910
|
+
const distance = Cesium.Cartesian3.distanceSquared(point.position, this.viewer.camera.positionWC || this.viewer.camera.position);
|
|
12911
|
+
const representativeDistance = Cesium.Cartesian3.distanceSquared(representative.position, this.viewer.camera.positionWC || this.viewer.camera.position);
|
|
12912
|
+
if (candidate.priority > appearance.priority || (candidate.priority === appearance.priority &&
|
|
12913
|
+
(distance < representativeDistance || (distance === representativeDistance &&
|
|
12914
|
+
point.id.localeCompare(representative.id) < 0)))) {
|
|
12915
|
+
representative = point;
|
|
12916
|
+
appearance = candidate;
|
|
12917
|
+
}
|
|
12918
|
+
}
|
|
12919
|
+
}
|
|
12920
|
+
const position = new Cesium.Cartesian3();
|
|
12921
|
+
for (const point of cluster.points) {
|
|
12922
|
+
Cesium.Cartesian3.add(position, point.position, position);
|
|
12923
|
+
}
|
|
12924
|
+
Cesium.Cartesian3.divideByScalar(position, cluster.points.length, position);
|
|
12925
|
+
const count = cluster.points.length;
|
|
10773
12926
|
const params = {
|
|
10774
|
-
size:
|
|
10775
|
-
txtColor: this.pointColorTxt,
|
|
10776
|
-
bgColor: this.pointColorBg,
|
|
12927
|
+
size: PointClusterSize(count),
|
|
10777
12928
|
text: String(count),
|
|
10778
|
-
iconUrl:
|
|
12929
|
+
iconUrl: appearance.iconUrl,
|
|
12930
|
+
bgColor: appearance.bgColor,
|
|
12931
|
+
txtColor: appearance.txtColor
|
|
10779
12932
|
};
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
let clusterEntity = this.clusterEntities.get(clusterId);
|
|
10786
|
-
const centroid = this.calculateCentroid(cluster.points);
|
|
10787
|
-
const count = cluster.points.length;
|
|
10788
|
-
if (clusterEntity) {
|
|
10789
|
-
clusterEntity.position = new Cesium.ConstantPositionProperty(Cesium.Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150));
|
|
10790
|
-
clusterEntity.billboard.image = new Cesium.CallbackProperty(() => {
|
|
10791
|
-
return getCanvas(count);
|
|
10792
|
-
}, false),
|
|
10793
|
-
clusterEntity.billboard.width = new Cesium.ConstantProperty(getScale(cluster.points.length));
|
|
10794
|
-
clusterEntity.billboard.height = new Cesium.ConstantProperty(getScale(cluster.points.length));
|
|
10795
|
-
}
|
|
10796
|
-
else {
|
|
10797
|
-
clusterEntity = this.viewer.entities.add({
|
|
10798
|
-
position: Cesium.Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150),
|
|
12933
|
+
const image = new Cesium.CallbackProperty(() => getClusterImage(params), false);
|
|
12934
|
+
let entity = this.clusterEntities.get(clusterId);
|
|
12935
|
+
if (!entity) {
|
|
12936
|
+
entity = this.viewer.entities.add({
|
|
12937
|
+
position,
|
|
10799
12938
|
billboard: {
|
|
12939
|
+
image,
|
|
12940
|
+
color: Cesium.Color.WHITE,
|
|
12941
|
+
width: params.size,
|
|
12942
|
+
height: params.size,
|
|
10800
12943
|
heightReference: Cesium.HeightReference.NONE,
|
|
10801
|
-
image: new Cesium.CallbackProperty(() => {
|
|
10802
|
-
return getCanvas(count);
|
|
10803
|
-
}, false),
|
|
10804
|
-
width: getScale(count),
|
|
10805
|
-
height: getScale(count),
|
|
10806
12944
|
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
|
10807
12945
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
|
10808
|
-
disableDepthTestDistance:
|
|
10809
|
-
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 0.5, 3.0e7, 0.1)
|
|
12946
|
+
disableDepthTestDistance: Infinity,
|
|
12947
|
+
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 0.5, 3.0e7, 0.1)
|
|
10810
12948
|
}
|
|
10811
12949
|
});
|
|
10812
|
-
this.clusterEntities.set(clusterId,
|
|
12950
|
+
this.clusterEntities.set(clusterId, entity);
|
|
12951
|
+
if (this.settings.selectOnClick !== false)
|
|
12952
|
+
this.picker.targets.set(entity, () => this.selectCluster(clusterId));
|
|
12953
|
+
}
|
|
12954
|
+
else {
|
|
12955
|
+
entity.position = new Cesium.ConstantPositionProperty(position);
|
|
12956
|
+
entity.billboard.image = image;
|
|
12957
|
+
entity.billboard.width = new Cesium.ConstantProperty(params.size);
|
|
12958
|
+
entity.billboard.height = new Cesium.ConstantProperty(params.size);
|
|
10813
12959
|
}
|
|
10814
|
-
|
|
10815
|
-
|
|
12960
|
+
const old = this.clusterViews.get(clusterId);
|
|
12961
|
+
this.clusterViews.set(clusterId, {
|
|
12962
|
+
entity,
|
|
12963
|
+
entityIds: cluster.points.map(point => point.id),
|
|
12964
|
+
representativeId: representative.id,
|
|
12965
|
+
selected: (_a = old === null || old === void 0 ? void 0 : old.selected) !== null && _a !== void 0 ? _a : false
|
|
12966
|
+
});
|
|
12967
|
+
_loadClusterImage(params).then(() => {
|
|
12968
|
+
if (!this.disposed && !this.viewer.isDestroyed()) {
|
|
12969
|
+
this.viewer.scene.requestRender();
|
|
12970
|
+
}
|
|
12971
|
+
});
|
|
12972
|
+
for (const point of cluster.points) {
|
|
10816
12973
|
const rego = this.register.GetRego({
|
|
10817
|
-
entityId:
|
|
12974
|
+
entityId: point.id,
|
|
10818
12975
|
menuItemId: this.menuItemId
|
|
10819
12976
|
});
|
|
10820
|
-
if (rego && rego.overrideShow
|
|
12977
|
+
if (rego && rego.overrideShow !== false) {
|
|
10821
12978
|
rego.overrideShow = false;
|
|
10822
|
-
|
|
12979
|
+
changed.add(point.id);
|
|
10823
12980
|
}
|
|
10824
12981
|
}
|
|
10825
12982
|
}
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
for (let [clusterId, clusterEntity] of Array.from(this.clusterEntities)) {
|
|
10829
|
-
if (!clusters.find(x => x.center.id == clusterId)) {
|
|
10830
|
-
this.viewer.entities.remove(clusterEntity);
|
|
10831
|
-
this.clusterEntities.delete(clusterId);
|
|
10832
|
-
}
|
|
12983
|
+
if (changed.size) {
|
|
12984
|
+
this.register.ForceUpdate({ entityIds: Array.from(changed) });
|
|
10833
12985
|
}
|
|
10834
|
-
this.
|
|
12986
|
+
this.refreshSelection();
|
|
10835
12987
|
}
|
|
10836
|
-
getClusterSpacing(
|
|
10837
|
-
|
|
10838
|
-
const distanceThresholds = [3000, 4000, 5300, 6000, 7000];
|
|
10839
|
-
// Distance increments in degrees.
|
|
10840
|
-
const distanceIncrements = [0.001, 0.002, 0.01, 0.03, 0.09];
|
|
10841
|
-
let index = 0;
|
|
10842
|
-
if (distanceFromCluster) {
|
|
10843
|
-
for (let i = 0; i < distanceThresholds.length; i++) {
|
|
10844
|
-
if (distanceFromCluster > distanceThresholds[i]) {
|
|
10845
|
-
index = i;
|
|
10846
|
-
}
|
|
10847
|
-
}
|
|
10848
|
-
}
|
|
10849
|
-
return distanceIncrements[index];
|
|
12988
|
+
getClusterSpacing(distance) {
|
|
12989
|
+
return distance > 7000 ? 0.09 : distance > 6000 ? 0.03 : distance > 5300 ? 0.01 : distance > 4000 ? 0.002 : 0.001;
|
|
10850
12990
|
}
|
|
10851
12991
|
getClusters() {
|
|
12992
|
+
const previous = new Set(this.currClusteredEntities);
|
|
10852
12993
|
this.currClusteredEntities.clear();
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
const
|
|
10856
|
-
|
|
10857
|
-
const
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
nearbyPoints = nearbyPoints.filter(x => !processedPoints.has(x.id) && !selectedIds.includes(x.id));
|
|
10882
|
-
if (nearbyPoints.length > 1) {
|
|
10883
|
-
let cluster = { center: point, points: [] };
|
|
10884
|
-
for (let nearby of nearbyPoints) {
|
|
10885
|
-
if (!cluster.points.includes(nearby)) {
|
|
10886
|
-
cluster.points.push(nearby);
|
|
10887
|
-
processedPoints.add(nearby.id);
|
|
10888
|
-
this.currClusteredEntities.add(nearby.id);
|
|
10889
|
-
}
|
|
10890
|
-
}
|
|
10891
|
-
clusters.push(cluster);
|
|
10892
|
-
}
|
|
10893
|
-
}
|
|
10894
|
-
}
|
|
10895
|
-
if (quad.divided) {
|
|
10896
|
-
processQuad(quad.northwest);
|
|
10897
|
-
processQuad(quad.northeast);
|
|
10898
|
-
processQuad(quad.southwest);
|
|
10899
|
-
processQuad(quad.southeast);
|
|
10900
|
-
}
|
|
10901
|
-
};
|
|
10902
|
-
processQuad(this.quadTree);
|
|
10903
|
-
// Filter out clusters with only one point.
|
|
10904
|
-
validClusters = clusters.filter((cluster) => cluster.points.length > 1);
|
|
12994
|
+
this.quadTree = new Quad(new Rectangle(0, 0, 360, 180), 30);
|
|
12995
|
+
const points = [];
|
|
12996
|
+
const distances = new Map();
|
|
12997
|
+
const camera = this.viewer.camera.positionWC || this.viewer.camera.position;
|
|
12998
|
+
const isolated = this.register.GetIsIsolatedAny();
|
|
12999
|
+
for (const [id, record] of this.records) {
|
|
13000
|
+
const state = this.register.GetState({ entityId: id, menuItemId: this.menuItemId });
|
|
13001
|
+
if (state.hidden || (isolated && !state.isolated)) {
|
|
13002
|
+
continue;
|
|
13003
|
+
}
|
|
13004
|
+
const geometry = this.resolveGeometry(record.visual);
|
|
13005
|
+
if (!geometry) {
|
|
13006
|
+
continue;
|
|
13007
|
+
}
|
|
13008
|
+
const { position, radius, minDistance } = geometry;
|
|
13009
|
+
const carto = Cesium.Cartographic.fromCartesian(position);
|
|
13010
|
+
if (!carto) {
|
|
13011
|
+
continue;
|
|
13012
|
+
}
|
|
13013
|
+
const point = new Point(Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude), id);
|
|
13014
|
+
point.position = position;
|
|
13015
|
+
point.radius = radius;
|
|
13016
|
+
point.minDistance = minDistance;
|
|
13017
|
+
if (!this.quadTree.Insert(point)) {
|
|
13018
|
+
continue;
|
|
13019
|
+
}
|
|
13020
|
+
points.push(point);
|
|
13021
|
+
distances.set(id, Cesium.Cartesian3.distance(position, camera));
|
|
10905
13022
|
}
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
const clusterEntity = this.clusterEntities.get(clusterId);
|
|
10918
|
-
if (clusterEntity) {
|
|
10919
|
-
this.viewer.entities.remove(clusterEntity);
|
|
10920
|
-
this.clusterEntities.delete(clusterId);
|
|
13023
|
+
const clusters = points.length < this.minTotalCount ? [] :
|
|
13024
|
+
ClusterItems({
|
|
13025
|
+
items: points.sort((a, b) => distances.get(a.id) - distances.get(b.id) || a.id.localeCompare(b.id)),
|
|
13026
|
+
id: point => point.id,
|
|
13027
|
+
eligible: point => Math.max(0, distances.get(point.id) - point.radius) > point.minDistance,
|
|
13028
|
+
neighbours: point => this.quadTree.Query(new Circle(point.lon, point.lat, this.getClusterSpacing(distances.get(point.id))), [])
|
|
13029
|
+
}).map(cluster => ({ center: cluster.representative, points: cluster.members }));
|
|
13030
|
+
for (const cluster of clusters) {
|
|
13031
|
+
for (const point of cluster.points) {
|
|
13032
|
+
this.currClusteredEntities.add(point.id);
|
|
13033
|
+
}
|
|
10921
13034
|
}
|
|
13035
|
+
return {
|
|
13036
|
+
clusters,
|
|
13037
|
+
noLongerClustered: new Set(Array.from(previous).filter(id => !this.currClusteredEntities.has(id)))
|
|
13038
|
+
};
|
|
10922
13039
|
}
|
|
10923
|
-
|
|
10924
|
-
const
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
* Adds new entity to the clustering logic.
|
|
10932
|
-
* @param id Bruce entity ID.
|
|
10933
|
-
* @param cartesian3 entity's position.
|
|
10934
|
-
*/
|
|
10935
|
-
addPoint(id, cartesian3) {
|
|
10936
|
-
let point = this.convertCartesianToCartographic(cartesian3);
|
|
10937
|
-
point.id = id;
|
|
10938
|
-
return this.quadTree.Insert(point);
|
|
13040
|
+
removeClusterEntity(id) {
|
|
13041
|
+
const entity = this.clusterEntities.get(id);
|
|
13042
|
+
if (!entity)
|
|
13043
|
+
return;
|
|
13044
|
+
this.picker.targets.delete(entity);
|
|
13045
|
+
this.viewer.entities.remove(entity);
|
|
13046
|
+
this.clusterEntities.delete(id);
|
|
13047
|
+
this.clusterViews.delete(id);
|
|
10939
13048
|
}
|
|
10940
|
-
|
|
10941
|
-
*
|
|
10942
|
-
* Will return false if entity could not be clustered and therefor should not be hidden.
|
|
10943
|
-
* @param id
|
|
10944
|
-
* @param entity
|
|
10945
|
-
* @param queueUpdate
|
|
10946
|
-
* @returns
|
|
13049
|
+
/*
|
|
13050
|
+
* Metadata is additive; existing three-argument calls keep their original signature.
|
|
10947
13051
|
*/
|
|
10948
|
-
AddEntity(id,
|
|
10949
|
-
if (this.disposed) {
|
|
10950
|
-
return false;
|
|
10951
|
-
}
|
|
10952
|
-
if (!entity) {
|
|
10953
|
-
return false;
|
|
10954
|
-
}
|
|
10955
|
-
if (entity.polygon || entity.polyline) {
|
|
10956
|
-
return false;
|
|
10957
|
-
}
|
|
10958
|
-
const pos3d = GetValue(this.viewer, entity.position);
|
|
10959
|
-
if (!(pos3d === null || pos3d === void 0 ? void 0 : pos3d.x)) {
|
|
13052
|
+
AddEntity(id, visual, queueUpdate = true, metadata = {}) {
|
|
13053
|
+
if (this.disposed || !visual) {
|
|
10960
13054
|
return false;
|
|
10961
13055
|
}
|
|
10962
|
-
if (!this.
|
|
10963
|
-
|
|
10964
|
-
if (pointColorBg) {
|
|
10965
|
-
let cColor = null;
|
|
10966
|
-
if (pointColorBg instanceof Object) {
|
|
10967
|
-
cColor = new Cesium.Color(pointColorBg.red, pointColorBg.green, pointColorBg.blue, pointColorBg.alpha);
|
|
10968
|
-
}
|
|
10969
|
-
else if (typeof pointColorBg === "string") {
|
|
10970
|
-
cColor = Cesium.Color.fromCssColorString(pointColorBg);
|
|
10971
|
-
}
|
|
10972
|
-
// Determine if text color should instead be black based on background.
|
|
10973
|
-
// cColor contains r,g,b,a values where r,g,b are in the range [0,1].
|
|
10974
|
-
if (cColor) {
|
|
10975
|
-
const brightness = (cColor.red * 299 + cColor.green * 587 + cColor.blue * 114) / 1000;
|
|
10976
|
-
if (brightness > 0.5) {
|
|
10977
|
-
this.pointColorTxt = "black";
|
|
10978
|
-
}
|
|
10979
|
-
else {
|
|
10980
|
-
this.pointColorTxt = "white";
|
|
10981
|
-
}
|
|
10982
|
-
this.pointColorBg = cColor.toCssColorString();
|
|
10983
|
-
}
|
|
10984
|
-
}
|
|
10985
|
-
}
|
|
10986
|
-
if (!this.iconUrl && entity.billboard) {
|
|
10987
|
-
const iconUrl = GetValue(this.viewer, entity.billboard.image);
|
|
10988
|
-
if (typeof iconUrl == "string") {
|
|
10989
|
-
this.iconUrl = iconUrl;
|
|
10990
|
-
}
|
|
10991
|
-
}
|
|
10992
|
-
if (this.registeredEntityIds.has(id)) {
|
|
10993
|
-
this.RemoveEntity(id, false);
|
|
10994
|
-
}
|
|
10995
|
-
const added = this.addPoint(id, pos3d);
|
|
10996
|
-
if (!added) {
|
|
13056
|
+
if (!this.resolveGeometry(visual)) {
|
|
13057
|
+
this.RemoveEntity(id, queueUpdate);
|
|
10997
13058
|
return false;
|
|
10998
13059
|
}
|
|
13060
|
+
this.records.set(id, { visual, metadata });
|
|
10999
13061
|
this.registeredEntityIds.add(id);
|
|
11000
13062
|
if (queueUpdate) {
|
|
11001
|
-
this.
|
|
13063
|
+
this.Update();
|
|
11002
13064
|
}
|
|
11003
13065
|
return true;
|
|
11004
13066
|
}
|
|
11005
|
-
/**
|
|
11006
|
-
* Removes entity from clustering logic.
|
|
11007
|
-
* Warning: This will not reveal the entity, suppressShow will remain true.
|
|
11008
|
-
* This is made with the assumption that the entity is being removed from viewer.
|
|
11009
|
-
* @param id
|
|
11010
|
-
* @param queueUpdate
|
|
11011
|
-
* @returns
|
|
11012
|
-
*/
|
|
11013
13067
|
RemoveEntity(id, queueUpdate = false) {
|
|
11014
13068
|
if (this.disposed) {
|
|
11015
13069
|
return;
|
|
11016
13070
|
}
|
|
11017
|
-
|
|
11018
|
-
if (pointToRemove) {
|
|
11019
|
-
this.quadTree.Remove(pointToRemove);
|
|
11020
|
-
if (queueUpdate) {
|
|
11021
|
-
this.updateQueue.Call();
|
|
11022
|
-
}
|
|
11023
|
-
}
|
|
13071
|
+
this.records.delete(id);
|
|
11024
13072
|
this.registeredEntityIds.delete(id);
|
|
13073
|
+
if (queueUpdate) {
|
|
13074
|
+
this.Update();
|
|
13075
|
+
}
|
|
11025
13076
|
}
|
|
11026
13077
|
}
|
|
11027
13078
|
|
|
@@ -11721,7 +13772,7 @@
|
|
|
11721
13772
|
});
|
|
11722
13773
|
this.useGeojson = item.renderAsGeojson == true;
|
|
11723
13774
|
if (item.enableClustering) {
|
|
11724
|
-
this.clustering = new PointClustering(this.visualsManager, this.item.id);
|
|
13775
|
+
this.clustering = new PointClustering(this.visualsManager, this.item.id, this.item.clustering);
|
|
11725
13776
|
}
|
|
11726
13777
|
}
|
|
11727
13778
|
Init(params) {
|
|
@@ -12757,8 +14808,8 @@
|
|
|
12757
14808
|
// The baseline data source must be editable.
|
|
12758
14809
|
const canEdit = !((_b = entity.Bruce.Outline) === null || _b === void 0 ? void 0 : _b.find(x => x.Baseline && !x.Editable));
|
|
12759
14810
|
const visual = rego === null || rego === void 0 ? void 0 : rego.visual;
|
|
14811
|
+
const wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false, { entity }) : false;
|
|
12760
14812
|
if (!visual || visual != cEntity) {
|
|
12761
|
-
const wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false) : false;
|
|
12762
14813
|
const tagIds = entity.Bruce["Layer.ID"];
|
|
12763
14814
|
const rego = {
|
|
12764
14815
|
canEdit: canEdit,
|
|
@@ -14193,8 +16244,8 @@
|
|
|
14193
16244
|
menuItemId: this.item.id
|
|
14194
16245
|
});
|
|
14195
16246
|
const visual = rego === null || rego === void 0 ? void 0 : rego.visual;
|
|
16247
|
+
const clustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false, { entity }) : false;
|
|
14196
16248
|
if (!visual || visual != cEntity) {
|
|
14197
|
-
const clustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false) : false;
|
|
14198
16249
|
this.visualsManager.AddRego({
|
|
14199
16250
|
rego: {
|
|
14200
16251
|
canEdit: true,
|
|
@@ -48073,7 +50124,7 @@ void main() {
|
|
|
48073
50124
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
48074
50125
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
48075
50126
|
|
|
48076
|
-
const VERSION = "7.
|
|
50127
|
+
const VERSION = "7.4.1";
|
|
48077
50128
|
/**
|
|
48078
50129
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
48079
50130
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|
|
@@ -48093,6 +50144,9 @@ void main() {
|
|
|
48093
50144
|
exports.VERSION = VERSION;
|
|
48094
50145
|
exports.setENVIRONMENT = setENVIRONMENT;
|
|
48095
50146
|
exports.getENVIRONMENT = getENVIRONMENT;
|
|
50147
|
+
exports.ClusterItems = ClusterItems;
|
|
50148
|
+
exports.PointClustering = PointClustering;
|
|
50149
|
+
exports.PointClusterSize = PointClusterSize;
|
|
48096
50150
|
exports.isStyleChanged = isStyleChanged;
|
|
48097
50151
|
exports.isOutlineChanged = isOutlineChanged$1;
|
|
48098
50152
|
exports.CesiumParabola = CesiumParabola;
|