bruce-cesium 7.4.2 → 7.4.4
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 +435 -234
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +433 -232
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-gatherer.js +50 -51
- package/dist/lib/rendering/entity-gatherer.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine.js +56 -26
- package/dist/lib/rendering/entity-render-engine.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label.js +325 -153
- package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/entity-gatherer.d.ts +2 -1
- package/dist/types/rendering/entity-render-engine.d.ts +1 -0
- package/dist/types/rendering/render-managers/common/entity-label.d.ts +6 -0
- package/package.json +1 -1
package/dist/bruce-cesium.es5.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Cesium from 'cesium';
|
|
2
|
-
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature,
|
|
3
|
-
import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Carto, Geometry as Geometry$1,
|
|
2
|
+
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, HeightReference, Matrix4, ColorBlendMode, ShadowMode, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ConstantPositionProperty, ArcType, CornerType, DistanceDisplayCondition, ShaderSource, Ellipsoid, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, FeatureDetection, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, Cesium3DTileColorBlendMode, HeadingPitchRange, Ion, IonResource, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, OrthographicFrustum, EasingFunction, CustomDataSource, PolygonPipeline, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, Intersect, GeometryInstance, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
|
|
3
|
+
import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Api, Carto, Geometry as Geometry$1, ClientFileValueMap, Color as Color$1, Bounds, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DataLab, DelayQueue, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, EntitySource, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType, EntityHistoricData } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -5403,8 +5403,16 @@ var EntityLabel;
|
|
|
5403
5403
|
// so a row of labels reads as one size rather than a set of differently shaped pills.
|
|
5404
5404
|
const ICON_BACKGROUND_UNIFORM_TOLERANCE = 0.3;
|
|
5405
5405
|
const TEXT_MAX_WIDTH = 200;
|
|
5406
|
+
// Distinct icons a cluster shows, the representative's included.
|
|
5407
|
+
const ICON_STACK_LIMIT = 3;
|
|
5408
|
+
// Size of every icon in a cluster's arrangement, relative to the representative's own.
|
|
5409
|
+
const ICON_STACK_SCALE = 0.6;
|
|
5406
5410
|
// How far an angled leader runs sideways before the label starts.
|
|
5407
5411
|
const ANGLED_LEADER_RUN = 28;
|
|
5412
|
+
// Clearance between a point or billboard glyph and the ring drawn around it.
|
|
5413
|
+
const ICON_RING_PADDING = 4;
|
|
5414
|
+
// Small points still get a ring as large as the default near ring.
|
|
5415
|
+
const ICON_RING_MIN = 10;
|
|
5408
5416
|
// One per tinted icon, since an SVG mask is addressed by id across the whole document.
|
|
5409
5417
|
let tintCounter = 0;
|
|
5410
5418
|
// Key where the label instance is stored within the cesium entity.
|
|
@@ -5586,6 +5594,28 @@ var EntityLabel;
|
|
|
5586
5594
|
* Prefer declared semantics; only infers from recognisable glyphs and filename tokens, never image pixels.
|
|
5587
5595
|
*/
|
|
5588
5596
|
EntityLabel.IconPriority = GetClusterIconPriority;
|
|
5597
|
+
function iconLook(options) {
|
|
5598
|
+
return {
|
|
5599
|
+
icon: options.icon || undefined,
|
|
5600
|
+
iconUrl: options.iconUrl || undefined,
|
|
5601
|
+
iconClass: typeof options.iconClass === "string" && options.iconClass ? options.iconClass : undefined,
|
|
5602
|
+
iconColor: typeof options.iconColor === "string" && options.iconColor ? options.iconColor : undefined,
|
|
5603
|
+
iconBackground: options.iconBackground || undefined
|
|
5604
|
+
};
|
|
5605
|
+
}
|
|
5606
|
+
/*
|
|
5607
|
+
* Everything that makes two labels look alike, so labels from different groups only merge when they would read the same.
|
|
5608
|
+
*/
|
|
5609
|
+
function clusterLook(options) {
|
|
5610
|
+
var _a;
|
|
5611
|
+
const presentation = options.presentation || "text";
|
|
5612
|
+
return JSON.stringify([
|
|
5613
|
+
presentation,
|
|
5614
|
+
(_a = options.leader) !== null && _a !== void 0 ? _a : null,
|
|
5615
|
+
options.leaderStyle || "default", options.leaderColor || "",
|
|
5616
|
+
presentation === "text" ? null : iconLook(options)
|
|
5617
|
+
]);
|
|
5618
|
+
}
|
|
5589
5619
|
/*
|
|
5590
5620
|
* Resolves clustering and stable text placement before depth fading; highlighted labels receive priority.
|
|
5591
5621
|
*/
|
|
@@ -5607,7 +5637,8 @@ var EntityLabel;
|
|
|
5607
5637
|
if (!((_b = (_a = frame.options) === null || _a === void 0 ? void 0 : _a.cluster) === null || _b === void 0 ? void 0 : _b.enabled) || frame.priority > 0) {
|
|
5608
5638
|
continue;
|
|
5609
5639
|
}
|
|
5610
|
-
|
|
5640
|
+
// Groups meet inside a presentation; which of them may merge is decided pairwise below.
|
|
5641
|
+
const key = frame.options.presentation || "text";
|
|
5611
5642
|
if (!groups.has(key)) {
|
|
5612
5643
|
groups.set(key, []);
|
|
5613
5644
|
}
|
|
@@ -5619,32 +5650,54 @@ var EntityLabel;
|
|
|
5619
5650
|
frame.options.cluster.pixelRange == null ? { ...frame, x: frame.anchorX, y: frame.anchorY, width: 1, height: 1 } :
|
|
5620
5651
|
frame.clusterBounds ? { ...frame, ...frame.clusterBounds } : frame);
|
|
5621
5652
|
const index = new ScreenIndex();
|
|
5622
|
-
|
|
5653
|
+
const rank = new Map();
|
|
5654
|
+
const looks = new Map();
|
|
5655
|
+
candidates.forEach((frame, i) => {
|
|
5623
5656
|
index.Add(frame);
|
|
5624
|
-
|
|
5657
|
+
rank.set(frame.id, i);
|
|
5658
|
+
looks.set(frame.id, clusterLook(frame.options));
|
|
5659
|
+
});
|
|
5625
5660
|
const clusters = ClusterItems({
|
|
5626
5661
|
items: candidates,
|
|
5627
5662
|
id: frame => frame.id,
|
|
5628
5663
|
minSize: group[0].options.cluster.minSize,
|
|
5629
5664
|
neighbours: frame => {
|
|
5630
5665
|
var _a;
|
|
5631
|
-
|
|
5666
|
+
const nearby = index.Query(frame, (_a = frame.options.cluster.pixelRange) !== null && _a !== void 0 ? _a : (frame.options.presentation === "icon" ? 24 : 8)).sort((a, b) => rank.get(a.id) - rank.get(b.id));
|
|
5667
|
+
return compatibleMembers(frame, nearby, other => other.group || "", other => looks.get(other.id));
|
|
5632
5668
|
}
|
|
5633
5669
|
});
|
|
5634
5670
|
for (const cluster of clusters) {
|
|
5635
5671
|
let chosen = cluster.representative;
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
}
|
|
5644
|
-
}
|
|
5672
|
+
const iconic = (chosen.options.presentation || "text") !== "text";
|
|
5673
|
+
// Members in the order they would win representation; the seed is the nearest.
|
|
5674
|
+
let ordered = [chosen, ...cluster.members.filter(member => member !== chosen)];
|
|
5675
|
+
if (iconic && chosen.options.cluster.representative !== "nearest") {
|
|
5676
|
+
ordered = ordered.map((member, i) => ({ member, i, priority: EntityLabel.IconPriority(member.options) }))
|
|
5677
|
+
.sort((a, b) => b.priority - a.priority || a.i - b.i).map(entry => entry.member);
|
|
5678
|
+
chosen = ordered[0];
|
|
5645
5679
|
}
|
|
5646
5680
|
const representative = result.get(chosen.id);
|
|
5647
5681
|
representative.members = cluster.members.map(frame => frame.id);
|
|
5682
|
+
if (iconic && chosen.options.iconScale !== 0) {
|
|
5683
|
+
const seen = new Set();
|
|
5684
|
+
const icons = [];
|
|
5685
|
+
for (const member of ordered) {
|
|
5686
|
+
const look = iconLook(member.options);
|
|
5687
|
+
const key = JSON.stringify(look);
|
|
5688
|
+
if (seen.has(key)) {
|
|
5689
|
+
continue;
|
|
5690
|
+
}
|
|
5691
|
+
seen.add(key);
|
|
5692
|
+
if (member !== ordered[0])
|
|
5693
|
+
icons.push(look);
|
|
5694
|
+
if (seen.size >= ICON_STACK_LIMIT) {
|
|
5695
|
+
break;
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
if (icons.length)
|
|
5699
|
+
representative.icons = icons;
|
|
5700
|
+
}
|
|
5648
5701
|
representative.entityIds = Array.from(new Set(cluster.members.map(frame => frame.entityId).filter(Boolean)));
|
|
5649
5702
|
if (chosen.options.presentation !== "icon") {
|
|
5650
5703
|
const values = new Set();
|
|
@@ -5697,6 +5750,34 @@ var EntityLabel;
|
|
|
5697
5750
|
return Array.from(result.values());
|
|
5698
5751
|
}
|
|
5699
5752
|
EntityLabel.Layout = Layout;
|
|
5753
|
+
/*
|
|
5754
|
+
* The seed plus every neighbour, in order, that shares a group or a look with each member accepted so far.
|
|
5755
|
+
*
|
|
5756
|
+
* Checking against the whole accepted set stops a group with mixed icons bridging two groups that look different.
|
|
5757
|
+
*/
|
|
5758
|
+
function compatibleMembers(seed, nearby, group, look) {
|
|
5759
|
+
const accepted = [seed];
|
|
5760
|
+
const byGroup = new Map([[group(seed), 1]]);
|
|
5761
|
+
const byLook = new Map([[look(seed), 1]]);
|
|
5762
|
+
const byBoth = new Map([[JSON.stringify([group(seed), look(seed)]), 1]]);
|
|
5763
|
+
for (const item of nearby) {
|
|
5764
|
+
if (item === seed) {
|
|
5765
|
+
continue;
|
|
5766
|
+
}
|
|
5767
|
+
const itemGroup = group(item), itemLook = look(item), both = JSON.stringify([itemGroup, itemLook]);
|
|
5768
|
+
// Accepted members in another group with another look are the ones this item may not sit beside.
|
|
5769
|
+
const conflicting = accepted.length - (byGroup.get(itemGroup) || 0) - (byLook.get(itemLook) || 0) + (byBoth.get(both) || 0);
|
|
5770
|
+
if (conflicting > 0) {
|
|
5771
|
+
continue;
|
|
5772
|
+
}
|
|
5773
|
+
accepted.push(item);
|
|
5774
|
+
byGroup.set(itemGroup, (byGroup.get(itemGroup) || 0) + 1);
|
|
5775
|
+
byLook.set(itemLook, (byLook.get(itemLook) || 0) + 1);
|
|
5776
|
+
byBoth.set(both, (byBoth.get(both) || 0) + 1);
|
|
5777
|
+
}
|
|
5778
|
+
return accepted;
|
|
5779
|
+
}
|
|
5780
|
+
EntityLabel.compatibleMembers = compatibleMembers;
|
|
5700
5781
|
const layers = new WeakMap();
|
|
5701
5782
|
const containers = new WeakMap();
|
|
5702
5783
|
/*
|
|
@@ -6094,7 +6175,7 @@ var EntityLabel;
|
|
|
6094
6175
|
* @param starterPos3d optional position to create label at. Ignored for billboard labels.
|
|
6095
6176
|
*/
|
|
6096
6177
|
async createLabel(starterPos3d) {
|
|
6097
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
|
|
6178
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
6098
6179
|
this.removeLabel();
|
|
6099
6180
|
let pos3d = starterPos3d ? starterPos3d.clone() : null;
|
|
6100
6181
|
const counter = ++this.counter;
|
|
@@ -6416,125 +6497,28 @@ var EntityLabel;
|
|
|
6416
6497
|
let iconElement;
|
|
6417
6498
|
let iconContainer;
|
|
6418
6499
|
let fitIconBackground;
|
|
6500
|
+
let iconStack;
|
|
6501
|
+
let stackedFits = [];
|
|
6502
|
+
let displayedStack = "[]";
|
|
6419
6503
|
content.className = "entity-label-content";
|
|
6420
6504
|
content.style.cssText = "display:flex;align-items:center;gap:6px;";
|
|
6421
6505
|
if (presentation === "icon-text-above") {
|
|
6422
6506
|
content.style.flexDirection = "column-reverse";
|
|
6423
6507
|
}
|
|
6424
6508
|
if (presentation !== "text") {
|
|
6425
|
-
const
|
|
6426
|
-
iconElement = icon;
|
|
6427
|
-
|
|
6428
|
-
icon.style.cssText = `font-size:${(this.options.iconSize || 24) * ((_m = this.options.iconScale) !== null && _m !== void 0 ? _m : 1)}px;line-height:1;`;
|
|
6429
|
-
icon.style.textShadow = "0 1px 2px rgba(0, 0, 0, 0.25)";
|
|
6430
|
-
const iconColor = typeof this.options.iconColor === "string" ? this.options.iconColor : undefined;
|
|
6431
|
-
const iconBackground = this.options.iconBackground && this.options.iconScale !== 0;
|
|
6432
|
-
if (iconColor) {
|
|
6433
|
-
icon.style.color = iconColor;
|
|
6434
|
-
}
|
|
6435
|
-
if (this.options.iconUrl) {
|
|
6436
|
-
const image = document.createElement("img");
|
|
6437
|
-
image.draggable = false;
|
|
6438
|
-
image.alt = this.options.icon || "";
|
|
6439
|
-
const scale = (_o = this.options.iconScale) !== null && _o !== void 0 ? _o : 1;
|
|
6440
|
-
const size = this.options.iconSize;
|
|
6441
|
-
const svgNs = "http://www.w3.org/2000/svg";
|
|
6442
|
-
const tint = iconColor ? document.createElementNS(svgNs, "svg") : null;
|
|
6443
|
-
const painted = tint ? document.createElementNS(svgNs, "image") : null;
|
|
6444
|
-
const inked = tint ? document.createElementNS(svgNs, "rect") : null;
|
|
6445
|
-
if (tint) {
|
|
6446
|
-
const maskId = `entity-label-tint-${++tintCounter}`;
|
|
6447
|
-
const mask = document.createElementNS(svgNs, "mask");
|
|
6448
|
-
mask.setAttribute("id", maskId);
|
|
6449
|
-
mask.setAttribute("maskUnits", "userSpaceOnUse");
|
|
6450
|
-
painted.setAttribute("href", this.options.iconUrl);
|
|
6451
|
-
painted.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
6452
|
-
mask.appendChild(painted);
|
|
6453
|
-
inked.setAttribute("fill", iconColor);
|
|
6454
|
-
inked.setAttribute("mask", `url(#${maskId})`);
|
|
6455
|
-
tint.append(mask, inked);
|
|
6456
|
-
tint.style.display = "block";
|
|
6457
|
-
icon.style.display = "inline-flex";
|
|
6458
|
-
icon.appendChild(tint);
|
|
6459
|
-
}
|
|
6460
|
-
const resize = () => {
|
|
6461
|
-
if (this.disposed || this.counter !== counter) {
|
|
6462
|
-
return;
|
|
6463
|
-
}
|
|
6464
|
-
const intrinsic = this.options.iconScale != null && size == null;
|
|
6465
|
-
const width = (intrinsic ? image.naturalWidth || 24 : size || 24) * scale;
|
|
6466
|
-
const height = (intrinsic ? image.naturalHeight || 24 : size || 24) * scale;
|
|
6467
|
-
if (tint) {
|
|
6468
|
-
tint.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
6469
|
-
for (const node of [tint, painted, inked]) {
|
|
6470
|
-
node.setAttribute("width", String(width));
|
|
6471
|
-
node.setAttribute("height", String(height));
|
|
6472
|
-
}
|
|
6473
|
-
}
|
|
6474
|
-
else {
|
|
6475
|
-
image.style.width = `${width}px`;
|
|
6476
|
-
image.style.height = `${height}px`;
|
|
6477
|
-
}
|
|
6478
|
-
this.viewer.scene.requestRender();
|
|
6479
|
-
};
|
|
6480
|
-
image.onload = resize;
|
|
6481
|
-
resize();
|
|
6482
|
-
image.src = this.options.iconUrl;
|
|
6483
|
-
if (!tint) {
|
|
6484
|
-
icon.appendChild(image);
|
|
6485
|
-
}
|
|
6486
|
-
}
|
|
6487
|
-
else if (typeof this.options.iconClass === "string" && this.options.iconClass) {
|
|
6488
|
-
icon.className = `entity-label-icon ${this.options.iconClass}`;
|
|
6489
|
-
}
|
|
6490
|
-
else {
|
|
6491
|
-
icon.textContent = this.options.icon || "●";
|
|
6492
|
-
}
|
|
6493
|
-
if (iconBackground) {
|
|
6494
|
-
const color = Color.fromCssColorString(iconColor || "white") || Color.WHITE;
|
|
6495
|
-
const luminance = 0.2126 * color.red + 0.7152 * color.green + 0.0722 * color.blue;
|
|
6496
|
-
const background = (luminance > 0.5 ? color.darken(ICON_BACKGROUND_BLEND, new Color()) :
|
|
6497
|
-
color.brighten(ICON_BACKGROUND_BLEND, new Color()));
|
|
6498
|
-
const size = (this.options.iconSize || 24) * ((_p = this.options.iconScale) !== null && _p !== void 0 ? _p : 1);
|
|
6499
|
-
icon.style.backgroundColor = background.withAlpha(ICON_BACKGROUND_ALPHA).toCssColorString();
|
|
6500
|
-
icon.style.borderRadius = "50%";
|
|
6501
|
-
icon.style.padding = `${size / 3}px`;
|
|
6502
|
-
icon.style.display = "inline-flex";
|
|
6503
|
-
icon.style.alignItems = "center";
|
|
6504
|
-
icon.style.justifyContent = "center";
|
|
6505
|
-
icon.style.minWidth = `${size}px`;
|
|
6506
|
-
icon.style.minHeight = `${size}px`;
|
|
6507
|
-
icon.style.boxSizing = "content-box";
|
|
6508
|
-
let fitted = false;
|
|
6509
|
-
fitIconBackground = () => {
|
|
6510
|
-
if (fitted) {
|
|
6511
|
-
return;
|
|
6512
|
-
}
|
|
6513
|
-
const padding = size / 3;
|
|
6514
|
-
const width = icon.offsetWidth - padding * 2;
|
|
6515
|
-
const height = icon.offsetHeight - padding * 2;
|
|
6516
|
-
if (width <= 0 || height <= 0) {
|
|
6517
|
-
return;
|
|
6518
|
-
}
|
|
6519
|
-
fitted = true;
|
|
6520
|
-
const longest = Math.max(width, height);
|
|
6521
|
-
const difference = (longest - Math.min(width, height)) / longest;
|
|
6522
|
-
if (difference > ICON_BACKGROUND_UNIFORM_TOLERANCE) {
|
|
6523
|
-
return;
|
|
6524
|
-
}
|
|
6525
|
-
icon.style.minWidth = `${longest}px`;
|
|
6526
|
-
icon.style.minHeight = `${longest}px`;
|
|
6527
|
-
this.viewer.scene.requestRender();
|
|
6528
|
-
};
|
|
6529
|
-
}
|
|
6530
|
-
if (this.options.iconScale === 0) {
|
|
6531
|
-
icon.style.display = "none";
|
|
6532
|
-
}
|
|
6509
|
+
const built = this.buildIcon(this.options, counter);
|
|
6510
|
+
const icon = iconElement = built.icon;
|
|
6511
|
+
fitIconBackground = built.fit;
|
|
6533
6512
|
makeClickable(icon);
|
|
6534
6513
|
// Keep badges outside the glyph so font classes and image masks cannot affect them.
|
|
6535
6514
|
iconContainer = document.createElement("span");
|
|
6536
|
-
iconContainer.style.cssText = "position:relative;display:inline-flex;flex:none;";
|
|
6537
|
-
|
|
6515
|
+
iconContainer.style.cssText = "position:relative;display:inline-flex;flex:none;align-items:center;";
|
|
6516
|
+
icon.style.position = "relative";
|
|
6517
|
+
iconStack = document.createElement("span");
|
|
6518
|
+
iconStack.className = "entity-label-icon-stack";
|
|
6519
|
+
iconStack.style.cssText = "display:none;gap:2px;align-items:center;justify-items:center;flex:none;";
|
|
6520
|
+
makeClickable(iconStack);
|
|
6521
|
+
iconContainer.append(iconStack, icon);
|
|
6538
6522
|
content.appendChild(iconContainer);
|
|
6539
6523
|
}
|
|
6540
6524
|
if (presentation !== "icon") {
|
|
@@ -6546,7 +6530,7 @@ var EntityLabel;
|
|
|
6546
6530
|
if (presentation === "text")
|
|
6547
6531
|
makeClickable(textElement);
|
|
6548
6532
|
content.appendChild(textElement);
|
|
6549
|
-
if ((
|
|
6533
|
+
if ((_m = this.options.cluster) === null || _m === void 0 ? void 0 : _m.enabled) {
|
|
6550
6534
|
sourceText = document.createElement("span");
|
|
6551
6535
|
sourceText.className = "entity-label-source-text";
|
|
6552
6536
|
sourceText.setAttribute("aria-hidden", "true");
|
|
@@ -6587,7 +6571,7 @@ var EntityLabel;
|
|
|
6587
6571
|
ele.appendChild(countElement);
|
|
6588
6572
|
}
|
|
6589
6573
|
ele.className = "entity-label";
|
|
6590
|
-
ele.dataset.entityId = ((
|
|
6574
|
+
ele.dataset.entityId = ((_o = this.rego) === null || _o === void 0 ? void 0 : _o.entityId) || "";
|
|
6591
6575
|
ele.dataset.presentation = presentation;
|
|
6592
6576
|
if (this.groupId) {
|
|
6593
6577
|
ele.dataset.groupId = this.groupId;
|
|
@@ -6703,6 +6687,41 @@ var EntityLabel;
|
|
|
6703
6687
|
run, side: (rightwards ? "right" : "left")
|
|
6704
6688
|
};
|
|
6705
6689
|
};
|
|
6690
|
+
/*
|
|
6691
|
+
* The on-screen centre and half-size of a point or billboard glyph, relative to its projected position.
|
|
6692
|
+
* Read every frame, since styling and selection can rescale a billboard in place.
|
|
6693
|
+
*/
|
|
6694
|
+
const measureIcon = () => {
|
|
6695
|
+
var _a;
|
|
6696
|
+
if (!normalLeader || !(visual instanceof Entity)) {
|
|
6697
|
+
return null;
|
|
6698
|
+
}
|
|
6699
|
+
if (visual.point) {
|
|
6700
|
+
const size = EnsureNumber(getValue(this.viewer, visual.point.pixelSize), 1) +
|
|
6701
|
+
EnsureNumber(getValue(this.viewer, visual.point.outlineWidth), 0) * 2;
|
|
6702
|
+
return size > 0 ? { x: 0, y: 0, radius: size / 2 } : null;
|
|
6703
|
+
}
|
|
6704
|
+
if (!visual.billboard) {
|
|
6705
|
+
return null;
|
|
6706
|
+
}
|
|
6707
|
+
const billboard = visual.billboard;
|
|
6708
|
+
const scale = EnsureNumber(getValue(this.viewer, billboard.scale), 1);
|
|
6709
|
+
// Icon billboards only record their image height; generated circles set both sides.
|
|
6710
|
+
const height = EnsureNumber((_a = getValue(this.viewer, billboard.height)) !== null && _a !== void 0 ? _a : billboard._billboardSize, 0) * scale;
|
|
6711
|
+
const width = EnsureNumber(getValue(this.viewer, billboard.width), height / scale) * scale;
|
|
6712
|
+
if (!(height > 0) || !(width > 0)) {
|
|
6713
|
+
return null;
|
|
6714
|
+
}
|
|
6715
|
+
const vertical = getValue(this.viewer, billboard.verticalOrigin);
|
|
6716
|
+
const horizontal = getValue(this.viewer, billboard.horizontalOrigin);
|
|
6717
|
+
const offset = getValue(this.viewer, billboard.pixelOffset);
|
|
6718
|
+
return {
|
|
6719
|
+
x: ((offset === null || offset === void 0 ? void 0 : offset.x) || 0) + (horizontal === HorizontalOrigin.LEFT ? width / 2 : horizontal === HorizontalOrigin.RIGHT ? -width / 2 : 0),
|
|
6720
|
+
y: ((offset === null || offset === void 0 ? void 0 : offset.y) || 0) + (vertical === VerticalOrigin.BOTTOM || vertical === VerticalOrigin.BASELINE ? -height / 2 :
|
|
6721
|
+
vertical === VerticalOrigin.TOP ? height / 2 : 0),
|
|
6722
|
+
radius: Math.max(width, height) / 2
|
|
6723
|
+
};
|
|
6724
|
+
};
|
|
6706
6725
|
let cursorMotion = this.cursorMotion;
|
|
6707
6726
|
const project = () => {
|
|
6708
6727
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
@@ -6769,9 +6788,13 @@ var EntityLabel;
|
|
|
6769
6788
|
this.cursorMotion = cursorMotion;
|
|
6770
6789
|
const cursorAmount = cursorMotion.amount;
|
|
6771
6790
|
leader = normalLeader || cursorAmount > 0;
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6791
|
+
// An icon keeps its callout centred on the glyph rather than following the cursor across it.
|
|
6792
|
+
const icon = measureIcon();
|
|
6793
|
+
const iconRing = icon ? Math.max(ICON_RING_MIN, icon.radius + ICON_RING_PADDING) : 0;
|
|
6794
|
+
const pivot = icon ? undefined : transientPivot;
|
|
6795
|
+
let x = ((_l = pivot === null || pivot === void 0 ? void 0 : pivot.x) !== null && _l !== void 0 ? _l : anchor.x) + (icon || pixelOffset).x;
|
|
6796
|
+
let y = ((_m = pivot === null || pivot === void 0 ? void 0 : pivot.y) !== null && _m !== void 0 ? _m : anchor.y) + (icon || pixelOffset).y;
|
|
6797
|
+
if (cursorAmount > 0 && !icon) {
|
|
6775
6798
|
// A leader-less label starts centred on its anchor; preserve that box as it lifts away.
|
|
6776
6799
|
if (!normalLeader) {
|
|
6777
6800
|
x -= ele.offsetWidth / layer.coordinates.scaleX / 2;
|
|
@@ -6809,9 +6832,11 @@ var EntityLabel;
|
|
|
6809
6832
|
if (cursorAmount > 0) {
|
|
6810
6833
|
leaderLength += (96 - leaderLength) * cursorAmount;
|
|
6811
6834
|
}
|
|
6835
|
+
// Measured from the ring, so the visible stem is the same length whatever the glyph's size.
|
|
6836
|
+
leaderLength += iconRing;
|
|
6812
6837
|
y = anchorY - leaderLength;
|
|
6813
6838
|
}
|
|
6814
|
-
else if (hover && !reused) {
|
|
6839
|
+
else if (hover && !reused && !icon) {
|
|
6815
6840
|
x = hover.x + pixelOffset.x;
|
|
6816
6841
|
y = hover.y + pixelOffset.y - 24;
|
|
6817
6842
|
}
|
|
@@ -6863,6 +6888,7 @@ var EntityLabel;
|
|
|
6863
6888
|
viewportWidth: this.viewer.canvas.clientWidth,
|
|
6864
6889
|
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,
|
|
6865
6890
|
entityId: (_t = this.rego) === null || _t === void 0 ? void 0 : _t.entityId, group: this.groupId, x, y, width, height, anchorX, anchorY, depth, leaderLength, leaderRun, leaderSide, distance,
|
|
6891
|
+
iconRadius: icon === null || icon === void 0 ? void 0 : icon.radius,
|
|
6866
6892
|
// Priority shows the hovered member individually without dragging its cluster along.
|
|
6867
6893
|
opacity, priority: hover || cursorAmount > 0 || (state === null || state === void 0 ? void 0 : state.highlighted) ? 1 : 0, options: this.options, text: originalText, clusterBounds
|
|
6868
6894
|
};
|
|
@@ -6870,7 +6896,7 @@ var EntityLabel;
|
|
|
6870
6896
|
let displacement = { x: 0, y: 0 };
|
|
6871
6897
|
let nudge = { x: 0, y: 0, fromX: 0, fromY: 0, targetX: 0, targetY: 0, start: 0 };
|
|
6872
6898
|
const apply = (placement) => {
|
|
6873
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
6899
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
|
|
6874
6900
|
const show = (placement === null || placement === void 0 ? void 0 : placement.visible) && placement.opacity > 0;
|
|
6875
6901
|
clickEntityIds = show ? placement.entityIds : [];
|
|
6876
6902
|
ele.style.visibility = show ? "visible" : "hidden";
|
|
@@ -6907,6 +6933,29 @@ var EntityLabel;
|
|
|
6907
6933
|
this.viewer.scene.requestRender();
|
|
6908
6934
|
}
|
|
6909
6935
|
fitIconBackground === null || fitIconBackground === void 0 ? void 0 : fitIconBackground();
|
|
6936
|
+
const stack = JSON.stringify(placement.icons || []);
|
|
6937
|
+
if (iconStack && stack !== displayedStack) {
|
|
6938
|
+
displayedStack = stack;
|
|
6939
|
+
const looks = ((_b = placement.icons) === null || _b === void 0 ? void 0 : _b.length) ? [iconLook(this.options), ...placement.icons] : [];
|
|
6940
|
+
// One small size for all, so no icon in the arrangement reads as more important than another.
|
|
6941
|
+
const size = (this.options.iconSize || 24) * ((_c = this.options.iconScale) !== null && _c !== void 0 ? _c : 1) * ICON_STACK_SCALE;
|
|
6942
|
+
const built = looks.map(look => this.buildIcon({ ...look, iconSize: size }, counter));
|
|
6943
|
+
// Two sit side by side; three make a triangle with the representative on top.
|
|
6944
|
+
iconStack.style.gridTemplateColumns = built.length === 3 ? "auto auto" : `repeat(${built.length}, auto)`;
|
|
6945
|
+
if (built.length === 3) {
|
|
6946
|
+
built[0].icon.style.gridColumn = "1 / span 2";
|
|
6947
|
+
}
|
|
6948
|
+
iconStack.replaceChildren(...built.map(({ icon }) => icon));
|
|
6949
|
+
iconStack.style.display = built.length ? "inline-grid" : "none";
|
|
6950
|
+
// The glyph stays measurable, since cluster membership is taken from its footprint.
|
|
6951
|
+
iconElement.style.visibility = built.length ? "hidden" : "";
|
|
6952
|
+
iconElement.style.position = built.length ? "absolute" : "relative";
|
|
6953
|
+
stackedFits = built.map(({ fit }) => fit).filter(Boolean);
|
|
6954
|
+
// The stack widens the label, which the next frame has to measure.
|
|
6955
|
+
this.viewer.scene.requestRender();
|
|
6956
|
+
}
|
|
6957
|
+
for (const fit of stackedFits)
|
|
6958
|
+
fit();
|
|
6910
6959
|
if (iconContainer) {
|
|
6911
6960
|
const badgeWidth = countElement.offsetWidth;
|
|
6912
6961
|
const iconWidth = iconElement.offsetWidth;
|
|
@@ -6922,36 +6971,43 @@ var EntityLabel;
|
|
|
6922
6971
|
// Summary and badge changes must fit on their first visible frame, including after resize.
|
|
6923
6972
|
const ring = this.options.anchorRing;
|
|
6924
6973
|
const pointer = (layer.pointer || (cursorMotion.target ? cursorMotion.position : undefined) || (this.Transient && !this.Persistent ?
|
|
6925
|
-
(this.hoverFade.to === 0 ? this.retainedHoverPosition : (
|
|
6926
|
-
const
|
|
6927
|
-
const
|
|
6974
|
+
(this.hoverFade.to === 0 ? this.retainedHoverPosition : (_d = this.visualRegister) === null || _d === void 0 ? void 0 : _d.GetLabelHoverPosition((_e = this.rego) === null || _e === void 0 ? void 0 : _e.entityId, (_f = this.rego) === null || _f === void 0 ? void 0 : _f.menuItemId)) : undefined));
|
|
6975
|
+
const iconRing = frame.iconRadius ? Math.max(ICON_RING_MIN, frame.iconRadius + ICON_RING_PADDING) : 0;
|
|
6976
|
+
const hovered = pointer && Math.hypot(pointer.x - frame.anchorX, pointer.y - frame.anchorY) <= Math.max((_g = ring === null || ring === void 0 ? void 0 : ring.hoverDistance) !== null && _g !== void 0 ? _g : 24, iconRing);
|
|
6977
|
+
const normalRadius = (!leader || (ring === null || ring === void 0 ? void 0 : ring.enabled) === false ? 0 : Math.max(frame.distance <= ((_h = ring === null || ring === void 0 ? void 0 : ring.nearDistance) !== null && _h !== void 0 ? _h : 100) ? ((_j = ring === null || ring === void 0 ? void 0 : ring.nearRadius) !== null && _j !== void 0 ? _j : 10) : 0, hovered ? ((_k = ring === null || ring === void 0 ? void 0 : ring.hoverRadius) !== null && _k !== void 0 ? _k : (this.Transient && !this.Persistent ? 15.4 : 22)) : 0));
|
|
6928
6978
|
const targetRadius = normalRadius + (15.4 - normalRadius) * cursorMotion.amount;
|
|
6979
|
+
// Around a glyph the ring keeps the glyph's size and only fades its stroke in, so it never covers the icon.
|
|
6980
|
+
const targetOuter = iconRing || targetRadius || 2.5;
|
|
6981
|
+
const targetInner = iconRing ? (targetRadius > 0 ? iconRing - 2 : iconRing) : Math.max(0, targetRadius - 2);
|
|
6929
6982
|
const now = Date.now();
|
|
6930
|
-
const duration = (
|
|
6983
|
+
const duration = (_l = ring === null || ring === void 0 ? void 0 : ring.transitionDuration) !== null && _l !== void 0 ? _l : 200;
|
|
6931
6984
|
const sharedRing = this.Transient && !this.Persistent && this.hoverFade.to === 1 ? this.hoverRingState : undefined;
|
|
6932
6985
|
let ringAnimation = sharedRing ? sharedRing.animation : this.ringAnimation;
|
|
6933
6986
|
if (!ringAnimation) {
|
|
6934
|
-
|
|
6987
|
+
const outer = iconRing || 2.5;
|
|
6988
|
+
const inner = iconRing;
|
|
6989
|
+
ringAnimation = { target: outer, targetInner: inner, start: now, outer, inner, fromOuter: outer, fromInner: inner };
|
|
6935
6990
|
}
|
|
6936
6991
|
const animateRing = () => {
|
|
6937
6992
|
const progress = duration > 0 ? Math.min(1, Math.max(0, (now - ringAnimation.start) / duration)) : 1;
|
|
6938
6993
|
const eased = progress * progress * (3 - 2 * progress);
|
|
6939
|
-
ringAnimation.outer = ringAnimation.fromOuter + (
|
|
6940
|
-
ringAnimation.inner = ringAnimation.fromInner + (
|
|
6994
|
+
ringAnimation.outer = ringAnimation.fromOuter + (ringAnimation.target - ringAnimation.fromOuter) * eased;
|
|
6995
|
+
ringAnimation.inner = ringAnimation.fromInner + (ringAnimation.targetInner - ringAnimation.fromInner) * eased;
|
|
6941
6996
|
return progress;
|
|
6942
6997
|
};
|
|
6943
6998
|
animateRing();
|
|
6944
|
-
if (ringAnimation.target !==
|
|
6999
|
+
if (ringAnimation.target !== targetOuter || ringAnimation.targetInner !== targetInner) {
|
|
6945
7000
|
ringAnimation = {
|
|
6946
7001
|
...ringAnimation,
|
|
6947
|
-
target:
|
|
7002
|
+
target: targetOuter,
|
|
7003
|
+
targetInner,
|
|
6948
7004
|
start: now,
|
|
6949
7005
|
fromOuter: ringAnimation.outer,
|
|
6950
7006
|
fromInner: ringAnimation.inner
|
|
6951
7007
|
};
|
|
6952
7008
|
}
|
|
6953
7009
|
// Animate the hole and stem together; no CSS transition may lag behind a moving world anchor.
|
|
6954
|
-
if (animateRing() < 1 && (ringAnimation.fromOuter !==
|
|
7010
|
+
if (animateRing() < 1 && (ringAnimation.fromOuter !== targetOuter || ringAnimation.fromInner !== targetInner)) {
|
|
6955
7011
|
this.viewer.scene.requestRender();
|
|
6956
7012
|
}
|
|
6957
7013
|
this.ringAnimation = ringAnimation;
|
|
@@ -6966,19 +7022,19 @@ var EntityLabel;
|
|
|
6966
7022
|
if (leader && angled) {
|
|
6967
7023
|
// The declutter owns the side; the fit only says which one had the room to begin with.
|
|
6968
7024
|
const run = Math.max(ANGLED_LEADER_RUN, radius + 4);
|
|
6969
|
-
const side = (
|
|
7025
|
+
const side = (_o = (_m = placement.textSide) !== null && _m !== void 0 ? _m : frame.leaderSide) !== null && _o !== void 0 ? _o : "right";
|
|
6970
7026
|
const beside = side === "left" ? frame.anchorX - run - width : frame.anchorX + run;
|
|
6971
7027
|
position.x = Math.max(0, Math.min(beside, this.viewer.canvas.clientWidth - width));
|
|
6972
7028
|
}
|
|
6973
7029
|
else if (leader && placement.textSide === "left") {
|
|
6974
7030
|
position.x = Math.max(0, Math.min(frame.anchorX - width, this.viewer.canvas.clientWidth - width));
|
|
6975
7031
|
}
|
|
6976
|
-
const gap = (
|
|
7032
|
+
const gap = (_q = (_p = this.options.pointerAvoidance) === null || _p === void 0 ? void 0 : _p.gap) !== null && _q !== void 0 ? _q : 12;
|
|
6977
7033
|
const containsPointer = (x, y, margin) => {
|
|
6978
7034
|
return pointer && pointer.x >= x - margin && pointer.x <= x + width + margin && pointer.y >= y - margin && pointer.y <= y + height + margin;
|
|
6979
7035
|
};
|
|
6980
7036
|
const passive = !selectOnClick || !this.visualRegister;
|
|
6981
|
-
if (passive && ((
|
|
7037
|
+
if (passive && ((_r = this.options.pointerAvoidance) === null || _r === void 0 ? void 0 : _r.enabled) !== false && pointer &&
|
|
6982
7038
|
(containsPointer(position.x, position.y, gap) || containsPointer(position.x + displacement.x, position.y + displacement.y, gap))) {
|
|
6983
7039
|
if (containsPointer(position.x + displacement.x, position.y + displacement.y, 0)) {
|
|
6984
7040
|
// Choose against the original box and retain the offset until the pointer leaves both boxes.
|
|
@@ -6996,7 +7052,7 @@ var EntityLabel;
|
|
|
6996
7052
|
else {
|
|
6997
7053
|
displacement = { x: 0, y: 0 };
|
|
6998
7054
|
}
|
|
6999
|
-
const nudgeDuration = (
|
|
7055
|
+
const nudgeDuration = (_t = (_s = this.options.pointerAvoidance) === null || _s === void 0 ? void 0 : _s.transitionDuration) !== null && _t !== void 0 ? _t : 200;
|
|
7000
7056
|
const animateNudge = () => {
|
|
7001
7057
|
const progress = now < nudge.start ? 0 : nudgeDuration > 0 ? Math.min(1, (now - nudge.start) / nudgeDuration) : 1;
|
|
7002
7058
|
const eased = progress * progress * (3 - 2 * progress);
|
|
@@ -7012,7 +7068,7 @@ var EntityLabel;
|
|
|
7012
7068
|
fromY: nudge.y,
|
|
7013
7069
|
targetX: displacement.x,
|
|
7014
7070
|
targetY: displacement.y,
|
|
7015
|
-
start: now + ((
|
|
7071
|
+
start: now + ((_v = (_u = this.options.pointerAvoidance) === null || _u === void 0 ? void 0 : _u.delay) !== null && _v !== void 0 ? _v : 180)
|
|
7016
7072
|
};
|
|
7017
7073
|
}
|
|
7018
7074
|
if (animateNudge() < 1 && (nudge.fromX !== nudge.targetX || nudge.fromY !== nudge.targetY)) {
|
|
@@ -7022,9 +7078,8 @@ var EntityLabel;
|
|
|
7022
7078
|
position.y += nudge.y;
|
|
7023
7079
|
ele.style.left = `${coordinates.x + position.x * coordinates.scaleX}px`;
|
|
7024
7080
|
ele.style.top = `${coordinates.y + position.y * coordinates.scaleY}px`;
|
|
7025
|
-
const clickTarget
|
|
7026
|
-
|
|
7027
|
-
clickTarget.setAttribute("aria-label", placement.members.length ? `Select ${placement.entityIds.length} entities` : `Select ${(_v = (_u = this.options.text) !== null && _u !== void 0 ? _u : text) !== null && _v !== void 0 ? _v : (_w = this.rego) === null || _w === void 0 ? void 0 : _w.entityId}`);
|
|
7081
|
+
for (const clickTarget of Array.from(content.querySelectorAll('[role="button"]'))) {
|
|
7082
|
+
clickTarget.setAttribute("aria-label", placement.members.length ? `Select ${placement.entityIds.length} entities` : `Select ${(_x = (_w = this.options.text) !== null && _w !== void 0 ? _w : text) !== null && _x !== void 0 ? _x : (_y = this.rego) === null || _y === void 0 ? void 0 : _y.entityId}`);
|
|
7028
7083
|
}
|
|
7029
7084
|
if (leader) {
|
|
7030
7085
|
const nodeRadius = ringAnimation.outer;
|
|
@@ -7064,13 +7119,13 @@ var EntityLabel;
|
|
|
7064
7119
|
// Keep the stem inside the 126-degree arc, away from antialiased endpoints.
|
|
7065
7120
|
const arcFraction = 0.35;
|
|
7066
7121
|
const rotationLimit = Math.PI * arcFraction - Math.PI / 30;
|
|
7067
|
-
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((
|
|
7122
|
+
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((_z = ringAnimation.arcOffset) !== null && _z !== void 0 ? _z : 0);
|
|
7068
7123
|
const targetOpen = cursorMotion.target || (hovered && (ring === null || ring === void 0 ? void 0 : ring.enabled) !== false && targetRadius > 0) ? 1 : 0;
|
|
7069
|
-
const elapsed = Math.min(32, Math.max(0, now - ((
|
|
7124
|
+
const elapsed = Math.min(32, Math.max(0, now - ((_0 = ringAnimation.arcTime) !== null && _0 !== void 0 ? _0 : now)));
|
|
7070
7125
|
const blend = duration > 0 ? 1 - Math.exp(-elapsed / (duration / 3)) : 1;
|
|
7071
7126
|
const approach = (value, target) => Math.abs(value - target) < 0.001 ? target : value + (target - value) * blend;
|
|
7072
|
-
ringAnimation.arcOffset = approach((
|
|
7073
|
-
ringAnimation.arcOpen = approach((
|
|
7127
|
+
ringAnimation.arcOffset = approach((_1 = ringAnimation.arcOffset) !== null && _1 !== void 0 ? _1 : 0, targetOffset);
|
|
7128
|
+
ringAnimation.arcOpen = approach((_2 = ringAnimation.arcOpen) !== null && _2 !== void 0 ? _2 : 0, targetOpen);
|
|
7074
7129
|
ringAnimation.arcTime = now;
|
|
7075
7130
|
if (ringAnimation.arcOffset !== targetOffset || ringAnimation.arcOpen !== targetOpen) {
|
|
7076
7131
|
this.viewer.scene.requestRender();
|
|
@@ -7123,6 +7178,123 @@ var EntityLabel;
|
|
|
7123
7178
|
}, 2500);
|
|
7124
7179
|
});
|
|
7125
7180
|
}
|
|
7181
|
+
/*
|
|
7182
|
+
* Builds one icon glyph from label options, with its background chip when asked for.
|
|
7183
|
+
*
|
|
7184
|
+
* The returned fit squares the chip off once the glyph has a measurable size.
|
|
7185
|
+
*/
|
|
7186
|
+
buildIcon(options, counter) {
|
|
7187
|
+
var _a, _b, _c;
|
|
7188
|
+
let fit;
|
|
7189
|
+
const icon = document.createElement("span");
|
|
7190
|
+
icon.className = "entity-label-icon";
|
|
7191
|
+
icon.style.cssText = `font-size:${(options.iconSize || 24) * ((_a = options.iconScale) !== null && _a !== void 0 ? _a : 1)}px;line-height:1;`;
|
|
7192
|
+
icon.style.textShadow = "0 1px 2px rgba(0, 0, 0, 0.25)";
|
|
7193
|
+
const iconColor = typeof options.iconColor === "string" ? options.iconColor : undefined;
|
|
7194
|
+
const iconBackground = options.iconBackground && options.iconScale !== 0;
|
|
7195
|
+
if (iconColor) {
|
|
7196
|
+
icon.style.color = iconColor;
|
|
7197
|
+
}
|
|
7198
|
+
if (options.iconUrl) {
|
|
7199
|
+
const image = document.createElement("img");
|
|
7200
|
+
image.draggable = false;
|
|
7201
|
+
image.alt = options.icon || "";
|
|
7202
|
+
const scale = (_b = options.iconScale) !== null && _b !== void 0 ? _b : 1;
|
|
7203
|
+
const size = options.iconSize;
|
|
7204
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
7205
|
+
const tint = iconColor ? document.createElementNS(svgNs, "svg") : null;
|
|
7206
|
+
const painted = tint ? document.createElementNS(svgNs, "image") : null;
|
|
7207
|
+
const inked = tint ? document.createElementNS(svgNs, "rect") : null;
|
|
7208
|
+
if (tint) {
|
|
7209
|
+
const maskId = `entity-label-tint-${++tintCounter}`;
|
|
7210
|
+
const mask = document.createElementNS(svgNs, "mask");
|
|
7211
|
+
mask.setAttribute("id", maskId);
|
|
7212
|
+
mask.setAttribute("maskUnits", "userSpaceOnUse");
|
|
7213
|
+
painted.setAttribute("href", options.iconUrl);
|
|
7214
|
+
painted.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
7215
|
+
mask.appendChild(painted);
|
|
7216
|
+
inked.setAttribute("fill", iconColor);
|
|
7217
|
+
inked.setAttribute("mask", `url(#${maskId})`);
|
|
7218
|
+
tint.append(mask, inked);
|
|
7219
|
+
tint.style.display = "block";
|
|
7220
|
+
icon.style.display = "inline-flex";
|
|
7221
|
+
icon.appendChild(tint);
|
|
7222
|
+
}
|
|
7223
|
+
const resize = () => {
|
|
7224
|
+
if (this.disposed || this.counter !== counter) {
|
|
7225
|
+
return;
|
|
7226
|
+
}
|
|
7227
|
+
const intrinsic = options.iconScale != null && size == null;
|
|
7228
|
+
const width = (intrinsic ? image.naturalWidth || 24 : size || 24) * scale;
|
|
7229
|
+
const height = (intrinsic ? image.naturalHeight || 24 : size || 24) * scale;
|
|
7230
|
+
if (tint) {
|
|
7231
|
+
tint.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
7232
|
+
for (const node of [tint, painted, inked]) {
|
|
7233
|
+
node.setAttribute("width", String(width));
|
|
7234
|
+
node.setAttribute("height", String(height));
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
7237
|
+
else {
|
|
7238
|
+
image.style.width = `${width}px`;
|
|
7239
|
+
image.style.height = `${height}px`;
|
|
7240
|
+
}
|
|
7241
|
+
this.viewer.scene.requestRender();
|
|
7242
|
+
};
|
|
7243
|
+
image.onload = resize;
|
|
7244
|
+
resize();
|
|
7245
|
+
image.src = options.iconUrl;
|
|
7246
|
+
if (!tint) {
|
|
7247
|
+
icon.appendChild(image);
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
else if (typeof options.iconClass === "string" && options.iconClass) {
|
|
7251
|
+
icon.className = `entity-label-icon ${options.iconClass}`;
|
|
7252
|
+
}
|
|
7253
|
+
else {
|
|
7254
|
+
icon.textContent = options.icon || "●";
|
|
7255
|
+
}
|
|
7256
|
+
if (iconBackground) {
|
|
7257
|
+
const color = Color.fromCssColorString(iconColor || "white") || Color.WHITE;
|
|
7258
|
+
const luminance = 0.2126 * color.red + 0.7152 * color.green + 0.0722 * color.blue;
|
|
7259
|
+
const background = (luminance > 0.5 ? color.darken(ICON_BACKGROUND_BLEND, new Color()) :
|
|
7260
|
+
color.brighten(ICON_BACKGROUND_BLEND, new Color()));
|
|
7261
|
+
const size = (options.iconSize || 24) * ((_c = options.iconScale) !== null && _c !== void 0 ? _c : 1);
|
|
7262
|
+
icon.style.backgroundColor = background.withAlpha(ICON_BACKGROUND_ALPHA).toCssColorString();
|
|
7263
|
+
icon.style.borderRadius = "50%";
|
|
7264
|
+
icon.style.padding = `${size / 3}px`;
|
|
7265
|
+
icon.style.display = "inline-flex";
|
|
7266
|
+
icon.style.alignItems = "center";
|
|
7267
|
+
icon.style.justifyContent = "center";
|
|
7268
|
+
icon.style.minWidth = `${size}px`;
|
|
7269
|
+
icon.style.minHeight = `${size}px`;
|
|
7270
|
+
icon.style.boxSizing = "content-box";
|
|
7271
|
+
let fitted = false;
|
|
7272
|
+
fit = () => {
|
|
7273
|
+
if (fitted) {
|
|
7274
|
+
return;
|
|
7275
|
+
}
|
|
7276
|
+
const padding = size / 3;
|
|
7277
|
+
const width = icon.offsetWidth - padding * 2;
|
|
7278
|
+
const height = icon.offsetHeight - padding * 2;
|
|
7279
|
+
if (width <= 0 || height <= 0) {
|
|
7280
|
+
return;
|
|
7281
|
+
}
|
|
7282
|
+
fitted = true;
|
|
7283
|
+
const longest = Math.max(width, height);
|
|
7284
|
+
const difference = (longest - Math.min(width, height)) / longest;
|
|
7285
|
+
if (difference > ICON_BACKGROUND_UNIFORM_TOLERANCE) {
|
|
7286
|
+
return;
|
|
7287
|
+
}
|
|
7288
|
+
icon.style.minWidth = `${longest}px`;
|
|
7289
|
+
icon.style.minHeight = `${longest}px`;
|
|
7290
|
+
this.viewer.scene.requestRender();
|
|
7291
|
+
};
|
|
7292
|
+
}
|
|
7293
|
+
if (options.iconScale === 0) {
|
|
7294
|
+
icon.style.display = "none";
|
|
7295
|
+
}
|
|
7296
|
+
return { icon, fit };
|
|
7297
|
+
}
|
|
7126
7298
|
/**
|
|
7127
7299
|
* Removes label from the viewer and unsubscribes from events.
|
|
7128
7300
|
*/
|
|
@@ -16796,9 +16968,6 @@ class EntityGatherer {
|
|
|
16796
16968
|
// Last date-time range taken from the clock.
|
|
16797
16969
|
this.lastDateTimeMin = null;
|
|
16798
16970
|
this.lastDateTimeMax = null;
|
|
16799
|
-
// Entity ID -> last resolved date time.
|
|
16800
|
-
// Helps determine if a slow resolved request can still be applied while we wait for the next one.
|
|
16801
|
-
this.lastFoundDateTimes = new Map();
|
|
16802
16971
|
// ID of Entity IDs that need to be requested.
|
|
16803
16972
|
this.eIdQueue = [];
|
|
16804
16973
|
// Membership mirror of eIdQueue for quick checks.
|
|
@@ -16830,8 +16999,12 @@ class EntityGatherer {
|
|
|
16830
16999
|
// Unsubscribes the view monitor listener that queues what the camera has moved onto.
|
|
16831
17000
|
this.monitorRemoval = null;
|
|
16832
17001
|
// Indicates a tick is active.
|
|
16833
|
-
// When true,
|
|
17002
|
+
// When true, a new tick is not started; it is noted in pendingTick and run once this one ends.
|
|
16834
17003
|
this.runningTick = false;
|
|
17004
|
+
// A tick was asked for while one was running, so another is owed once it finishes.
|
|
17005
|
+
this.pendingTick = false;
|
|
17006
|
+
// The debounce every clock change goes through, kept so a tick owed after a running one does too.
|
|
17007
|
+
this.tickDelay = null;
|
|
16835
17008
|
// Entity ID -> Entity blob.
|
|
16836
17009
|
// This is a tool that lets developers set their own JSON blobs instead of requesting data from API.
|
|
16837
17010
|
this.entityDataOverrides = new Map();
|
|
@@ -16895,11 +17068,13 @@ class EntityGatherer {
|
|
|
16895
17068
|
let tickDelay = new DelayQueue(() => {
|
|
16896
17069
|
this.onTick(false);
|
|
16897
17070
|
}, 250, true);
|
|
17071
|
+
this.tickDelay = tickDelay;
|
|
16898
17072
|
this.hDisposals.push(() => {
|
|
16899
17073
|
if (tickDelay) {
|
|
16900
17074
|
tickDelay.Dispose();
|
|
16901
17075
|
}
|
|
16902
17076
|
tickDelay = null;
|
|
17077
|
+
this.tickDelay = null;
|
|
16903
17078
|
});
|
|
16904
17079
|
// React to clock changes and request new Entities.
|
|
16905
17080
|
let prevTime = null;
|
|
@@ -16939,7 +17114,6 @@ class EntityGatherer {
|
|
|
16939
17114
|
this.priorityCount = 0;
|
|
16940
17115
|
this.lastOrderFocus = null;
|
|
16941
17116
|
this.allEIds.clear();
|
|
16942
|
-
this.lastFoundDateTimes.clear();
|
|
16943
17117
|
this.everFound.clear();
|
|
16944
17118
|
this.clearIndex();
|
|
16945
17119
|
this.lastDateTime = null;
|
|
@@ -17301,7 +17475,6 @@ class EntityGatherer {
|
|
|
17301
17475
|
this.eIdQueued.clear();
|
|
17302
17476
|
this.priorityCount = 0;
|
|
17303
17477
|
this.allEIds.clear();
|
|
17304
|
-
this.lastFoundDateTimes.clear();
|
|
17305
17478
|
this.everFound.clear();
|
|
17306
17479
|
this.clearIndex();
|
|
17307
17480
|
this.entityDataOverrides.clear();
|
|
@@ -17317,7 +17490,13 @@ class EntityGatherer {
|
|
|
17317
17490
|
}
|
|
17318
17491
|
}
|
|
17319
17492
|
onTick(force) {
|
|
17320
|
-
if (this.
|
|
17493
|
+
if (this.disposed) {
|
|
17494
|
+
return;
|
|
17495
|
+
}
|
|
17496
|
+
if (this.runningTick) {
|
|
17497
|
+
if (this.historic) {
|
|
17498
|
+
this.pendingTick = true;
|
|
17499
|
+
}
|
|
17321
17500
|
return;
|
|
17322
17501
|
}
|
|
17323
17502
|
const rTime = this.viewer.clock.currentTime.toString();
|
|
@@ -17325,10 +17504,16 @@ class EntityGatherer {
|
|
|
17325
17504
|
return;
|
|
17326
17505
|
}
|
|
17327
17506
|
this.lastDateTime = rTime;
|
|
17507
|
+
// Whether the clock has left the moment this tick is reading.
|
|
17508
|
+
const movedOn = () => this.historic && this.viewer.clock.currentTime.toString() !== rTime;
|
|
17328
17509
|
(async () => {
|
|
17329
17510
|
this.runningTick = true;
|
|
17511
|
+
this.pendingTick = false;
|
|
17330
17512
|
this.placeStragglers();
|
|
17331
17513
|
let rerun = false;
|
|
17514
|
+
let interrupted = false;
|
|
17515
|
+
// Batch's answer is applied while the next batch is being read.
|
|
17516
|
+
const applying = [];
|
|
17332
17517
|
try {
|
|
17333
17518
|
const handleResponse = async (requestedBatch, entities) => {
|
|
17334
17519
|
var _a, _b, _c, _d;
|
|
@@ -17392,45 +17577,7 @@ class EntityGatherer {
|
|
|
17392
17577
|
api: this.api
|
|
17393
17578
|
})).tags;
|
|
17394
17579
|
}
|
|
17395
|
-
|
|
17396
|
-
// 1 = rTime is in the future.
|
|
17397
|
-
// -1 = rTime is in the past.
|
|
17398
|
-
let changeDir = 0;
|
|
17399
|
-
if (this.lastDateTime !== this.viewer.clock.currentTime.toString()) {
|
|
17400
|
-
changeDir = this.lastDateTime < this.viewer.clock.currentTime.toString() ? 1 : -1;
|
|
17401
|
-
}
|
|
17402
|
-
let toEmit;
|
|
17403
|
-
if (this.historic) {
|
|
17404
|
-
// We can emit Entities if the last resolved time (per Entity) isn't newer than rTime.
|
|
17405
|
-
// We compare using the changeDir to determine if we should emit or not.
|
|
17406
|
-
toEmit = resolvedEntities.filter((e) => {
|
|
17407
|
-
var _a;
|
|
17408
|
-
const entityId = ((_a = e === null || e === void 0 ? void 0 : e.Bruce) === null || _a === void 0 ? void 0 : _a.ID) || (e === null || e === void 0 ? void 0 : e.id);
|
|
17409
|
-
const lastFoundDateTime = this.lastFoundDateTimes.get(entityId);
|
|
17410
|
-
if (lastFoundDateTime) {
|
|
17411
|
-
if (changeDir === 1) {
|
|
17412
|
-
return lastFoundDateTime <= rTime;
|
|
17413
|
-
}
|
|
17414
|
-
else if (changeDir === -1) {
|
|
17415
|
-
return lastFoundDateTime >= rTime;
|
|
17416
|
-
}
|
|
17417
|
-
}
|
|
17418
|
-
return true;
|
|
17419
|
-
});
|
|
17420
|
-
// Update the last found date times for the filtered Entities.
|
|
17421
|
-
toEmit.forEach((e) => {
|
|
17422
|
-
var _a;
|
|
17423
|
-
const entityId = ((_a = e === null || e === void 0 ? void 0 : e.Bruce) === null || _a === void 0 ? void 0 : _a.ID) || (e === null || e === void 0 ? void 0 : e.id);
|
|
17424
|
-
if (entityId) {
|
|
17425
|
-
this.lastFoundDateTimes.set(entityId, rTime);
|
|
17426
|
-
}
|
|
17427
|
-
});
|
|
17428
|
-
}
|
|
17429
|
-
else {
|
|
17430
|
-
// If we're not historic, we can just emit everything.
|
|
17431
|
-
toEmit = resolvedEntities;
|
|
17432
|
-
}
|
|
17433
|
-
this.emitEntities(toEmit, tags);
|
|
17580
|
+
this.emitEntities(resolvedEntities, tags);
|
|
17434
17581
|
};
|
|
17435
17582
|
const QUEUE_BATCH_SIZE = 500;
|
|
17436
17583
|
const requestedIds = new Set();
|
|
@@ -17439,7 +17586,8 @@ class EntityGatherer {
|
|
|
17439
17586
|
const total = this.eIdQueue.length;
|
|
17440
17587
|
let done = 0;
|
|
17441
17588
|
while (this.eIdQueue.length && !this.disposed) {
|
|
17442
|
-
if (
|
|
17589
|
+
if (movedOn()) {
|
|
17590
|
+
interrupted = true;
|
|
17443
17591
|
break;
|
|
17444
17592
|
}
|
|
17445
17593
|
this.orderQueueByCamera();
|
|
@@ -17455,7 +17603,7 @@ class EntityGatherer {
|
|
|
17455
17603
|
api: this.api,
|
|
17456
17604
|
maxSearchTimeSec: 60 * 2
|
|
17457
17605
|
});
|
|
17458
|
-
handleResponse(batch, entities);
|
|
17606
|
+
applying.push(handleResponse(batch, entities));
|
|
17459
17607
|
for (let i = 0; i < batch.length; i++) {
|
|
17460
17608
|
requestedIds.add(batch[i]);
|
|
17461
17609
|
}
|
|
@@ -17487,7 +17635,8 @@ class EntityGatherer {
|
|
|
17487
17635
|
// The near ones are resolved first out of whatever the view still reaches.
|
|
17488
17636
|
allEIds = this.bandIds(allEIds);
|
|
17489
17637
|
while (allEIds.length && !this.disposed && !this.eIdQueue.length) {
|
|
17490
|
-
if (
|
|
17638
|
+
if (movedOn()) {
|
|
17639
|
+
interrupted = true;
|
|
17491
17640
|
break;
|
|
17492
17641
|
}
|
|
17493
17642
|
const batch = allEIds.splice(0, QUEUE_BATCH_SIZE);
|
|
@@ -17498,7 +17647,7 @@ class EntityGatherer {
|
|
|
17498
17647
|
api: this.api,
|
|
17499
17648
|
maxSearchTimeSec: 60 * 2
|
|
17500
17649
|
});
|
|
17501
|
-
handleResponse(batch, entities);
|
|
17650
|
+
applying.push(handleResponse(batch, entities));
|
|
17502
17651
|
for (let i = 0; i < batch.length; i++) {
|
|
17503
17652
|
requestedIds.add(batch[i]);
|
|
17504
17653
|
}
|
|
@@ -17513,10 +17662,32 @@ class EntityGatherer {
|
|
|
17513
17662
|
console.error(e);
|
|
17514
17663
|
}
|
|
17515
17664
|
finally {
|
|
17665
|
+
// Only a historic answer can be overtaken by a newer moment, so nothing else waits.
|
|
17666
|
+
if (this.historic && applying.length) {
|
|
17667
|
+
await Promise.all(applying.map((pending) => pending.catch((e) => console.error(e))));
|
|
17668
|
+
}
|
|
17516
17669
|
this.runningTick = false;
|
|
17517
17670
|
}
|
|
17518
|
-
|
|
17671
|
+
// A moment read only in part is forgotten, so coming back to it reads it again in full.
|
|
17672
|
+
if (interrupted && this.lastDateTime === rTime) {
|
|
17673
|
+
this.lastDateTime = null;
|
|
17674
|
+
}
|
|
17675
|
+
if (this.disposed) {
|
|
17676
|
+
return;
|
|
17677
|
+
}
|
|
17678
|
+
// Leftovers at the same moment carry straight on, as they always have.
|
|
17679
|
+
if (rerun && !interrupted) {
|
|
17519
17680
|
this.onTick(true);
|
|
17681
|
+
return;
|
|
17682
|
+
}
|
|
17683
|
+
if (interrupted || this.pendingTick || movedOn()) {
|
|
17684
|
+
this.pendingTick = false;
|
|
17685
|
+
if (this.tickDelay) {
|
|
17686
|
+
this.tickDelay.Call();
|
|
17687
|
+
}
|
|
17688
|
+
else {
|
|
17689
|
+
this.onTick(false);
|
|
17690
|
+
}
|
|
17520
17691
|
}
|
|
17521
17692
|
})();
|
|
17522
17693
|
}
|
|
@@ -49206,7 +49377,7 @@ var EntityRenderEngine;
|
|
|
49206
49377
|
}
|
|
49207
49378
|
EntityRenderEngine.GetGraphicShapeId = GetGraphicShapeId;
|
|
49208
49379
|
async function Render(params) {
|
|
49209
|
-
var _a, _b, _c;
|
|
49380
|
+
var _a, _b, _c, _d, _e;
|
|
49210
49381
|
const groupRenderParams = {
|
|
49211
49382
|
apiGetter: params.apiGetter,
|
|
49212
49383
|
viewer: params.viewer,
|
|
@@ -49383,10 +49554,20 @@ var EntityRenderEngine;
|
|
|
49383
49554
|
polygons.push(entity);
|
|
49384
49555
|
continue;
|
|
49385
49556
|
}
|
|
49557
|
+
// Present when the gate above chose to reuse this entity's graphic.
|
|
49558
|
+
const existingRoot = cEntities.get(entity.Bruce.ID);
|
|
49559
|
+
const existingParts = new Map();
|
|
49560
|
+
(_d = existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) === null || _d === void 0 ? void 0 : _d.forEach((part) => {
|
|
49561
|
+
if (part._multiPartIndex != null) {
|
|
49562
|
+
existingParts.set(part._multiPartIndex, part);
|
|
49563
|
+
}
|
|
49564
|
+
});
|
|
49565
|
+
const partRendered = new Map();
|
|
49566
|
+
const partIndexes = new Map();
|
|
49386
49567
|
const pParams = {
|
|
49387
49568
|
...groupRenderParams,
|
|
49388
49569
|
entities: [],
|
|
49389
|
-
rendered:
|
|
49570
|
+
rendered: partRendered
|
|
49390
49571
|
};
|
|
49391
49572
|
pParams.entitiesHistoric = params.entitiesHistoric;
|
|
49392
49573
|
const zoomItem = pParams.zoomItems[entity.Bruce.ID];
|
|
@@ -49402,39 +49583,59 @@ var EntityRenderEngine;
|
|
|
49402
49583
|
};
|
|
49403
49584
|
pParams.zoomItems[subEntity.Bruce.ID] = zoomItem;
|
|
49404
49585
|
pParams.entities.push(subEntity);
|
|
49405
|
-
|
|
49406
|
-
|
|
49407
|
-
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
|
|
49411
|
-
|
|
49412
|
-
|
|
49413
|
-
|
|
49414
|
-
|
|
49415
|
-
|
|
49586
|
+
partIndexes.set(subEntity.Bruce.ID, j);
|
|
49587
|
+
const existingPart = existingParts.get(j);
|
|
49588
|
+
if (existingPart) {
|
|
49589
|
+
// An engine preparing a reused graphic gathers everything connected to it, so a part still
|
|
49590
|
+
// attached to its root would have every other part evicted from the scene.
|
|
49591
|
+
existingPart._parentEntity = null;
|
|
49592
|
+
partRendered.set(subEntity.Bruce.ID, existingPart);
|
|
49593
|
+
}
|
|
49594
|
+
}
|
|
49595
|
+
const rendered = [];
|
|
49596
|
+
const collect = (results) => {
|
|
49597
|
+
results.forEach((cEntity, key) => {
|
|
49598
|
+
if (!cEntity) {
|
|
49599
|
+
return;
|
|
49600
|
+
}
|
|
49601
|
+
cEntity._multiPartIndex = partIndexes.get(key);
|
|
49602
|
+
rendered.push(cEntity);
|
|
49416
49603
|
pParams.entities = pParams.entities.filter((e) => e.Bruce.ID != key);
|
|
49417
|
-
}
|
|
49418
|
-
}
|
|
49419
|
-
|
|
49604
|
+
});
|
|
49605
|
+
};
|
|
49606
|
+
collect(await Polygon.RenderGroup(pParams));
|
|
49607
|
+
collect(await Polyline.RenderGroup(pParams));
|
|
49420
49608
|
// We'll only render points when there's no other geometry.
|
|
49421
49609
|
// Generally speaking when polygons/polylines are drawn, points are only drawn because of invalid data.
|
|
49422
49610
|
if (!rendered.length) {
|
|
49423
|
-
|
|
49424
|
-
rendered = rendered.concat(Array.from(cPoints.values()));
|
|
49611
|
+
collect(await Point.RenderGroup(pParams));
|
|
49425
49612
|
}
|
|
49426
|
-
rendered = rendered.filter(x => x != null);
|
|
49427
49613
|
if (rendered.length) {
|
|
49428
|
-
const
|
|
49429
|
-
|
|
49430
|
-
|
|
49431
|
-
|
|
49614
|
+
const sameParts = ((_e = existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) === null || _e === void 0 ? void 0 : _e.length) == rendered.length &&
|
|
49615
|
+
rendered.every((part) => existingRoot._siblingGraphics.includes(part));
|
|
49616
|
+
let rootEntity;
|
|
49617
|
+
if (sameParts) {
|
|
49618
|
+
rootEntity = existingRoot;
|
|
49619
|
+
}
|
|
49620
|
+
else {
|
|
49621
|
+
if (existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) {
|
|
49622
|
+
// Retiring the old root removes its parts, and the ones carried over belong to the new root now.
|
|
49623
|
+
existingRoot._siblingGraphics = existingRoot._siblingGraphics.filter((part) => !rendered.includes(part));
|
|
49624
|
+
}
|
|
49625
|
+
rootEntity = new Entity({
|
|
49626
|
+
id: ObjectUtils.UId(15)
|
|
49627
|
+
});
|
|
49628
|
+
}
|
|
49629
|
+
rootEntity._siblingGraphics = rendered;
|
|
49432
49630
|
rootEntity._renderGroup = GetRenderGroupId(zoomItem);
|
|
49433
|
-
|
|
49631
|
+
// The skip gate compares the rego's style against the zoom item's, and the rego takes it from here.
|
|
49632
|
+
rootEntity.styleId = (zoomItem === null || zoomItem === void 0 ? void 0 : zoomItem.StyleID) == -1 ? -1 : (+(zoomItem === null || zoomItem === void 0 ? void 0 : zoomItem.StyleID) || null);
|
|
49633
|
+
rootEntity.styleEffective = rendered[0].styleEffective;
|
|
49434
49634
|
cEntities.set(entity.Bruce.ID, rootEntity);
|
|
49435
|
-
const
|
|
49436
|
-
|
|
49437
|
-
|
|
49635
|
+
const newPosition = GetCValue(params.viewer, rendered[0].position);
|
|
49636
|
+
const oldPosition = GetCValue(params.viewer, rootEntity.position);
|
|
49637
|
+
if (newPosition && (!oldPosition || !Cartes.IsEqualCartes3(oldPosition, newPosition))) {
|
|
49638
|
+
rootEntity.position = new ConstantPositionProperty(newPosition);
|
|
49438
49639
|
}
|
|
49439
49640
|
rendered.forEach((child) => {
|
|
49440
49641
|
child._parentEntity = rootEntity;
|
|
@@ -50371,7 +50572,7 @@ var StyleUtils;
|
|
|
50371
50572
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
50372
50573
|
})(StyleUtils || (StyleUtils = {}));
|
|
50373
50574
|
|
|
50374
|
-
const VERSION = "7.4.
|
|
50575
|
+
const VERSION = "7.4.4";
|
|
50375
50576
|
/**
|
|
50376
50577
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
50377
50578
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|