bruce-cesium 7.4.3 → 7.4.5
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 +332 -158
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +330 -156
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label.js +329 -155
- 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/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,
|
|
2
|
+
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, ShaderSource, Cartesian3, Math as Math$1, Ellipsoid, Transforms, Matrix4, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, JulianDate, Quaternion, HeadingPitchRoll, HeightReference, ConstantPositionProperty, DistanceDisplayCondition, ColorBlendMode, ShadowMode, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, ArcType, CornerType, Rectangle, SceneTransforms, FeatureDetection, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, Ion, IonResource, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, OrthographicFrustum, EasingFunction, Intersect, CustomDataSource, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, GeometryInstance, PolygonPipeline, 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, Bounds, ClientFileValueMap, Color as Color$1, Geometry as Geometry$1, Carto, 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;
|
|
@@ -6730,8 +6749,10 @@ var EntityLabel;
|
|
|
6730
6749
|
const relative = Cartesian3.subtract(this._pos3d, cameraPosition, new Cartesian3());
|
|
6731
6750
|
const depth = Cartesian3.dot(relative, camera.directionWC || camera.direction);
|
|
6732
6751
|
const distance = Cartesian3.magnitude(relative);
|
|
6752
|
+
// If we're labelling from a temp label (mouse hover) don't drive opacity by cam distance.
|
|
6753
|
+
const hoverOnly = this.Transient && !this.Persistent;
|
|
6733
6754
|
if (!Number.isFinite(distance) || depth <= 0 || distance < ((_c = this.options.near) !== null && _c !== void 0 ? _c : 0) ||
|
|
6734
|
-
distance > ((_d = this.options.far) !== null && _d !== void 0 ? _d : Infinity) || (!this.prePositioned && distance >= MAX_DISTANCE)) {
|
|
6755
|
+
distance > ((_d = this.options.far) !== null && _d !== void 0 ? _d : Infinity) || (!this.prePositioned && !hoverOnly && distance >= MAX_DISTANCE)) {
|
|
6735
6756
|
return null;
|
|
6736
6757
|
}
|
|
6737
6758
|
const transforms = SceneTransforms;
|
|
@@ -6769,9 +6790,13 @@ var EntityLabel;
|
|
|
6769
6790
|
this.cursorMotion = cursorMotion;
|
|
6770
6791
|
const cursorAmount = cursorMotion.amount;
|
|
6771
6792
|
leader = normalLeader || cursorAmount > 0;
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6793
|
+
// An icon keeps its callout centred on the glyph rather than following the cursor across it.
|
|
6794
|
+
const icon = measureIcon();
|
|
6795
|
+
const iconRing = icon ? Math.max(ICON_RING_MIN, icon.radius + ICON_RING_PADDING) : 0;
|
|
6796
|
+
const pivot = icon ? undefined : transientPivot;
|
|
6797
|
+
let x = ((_l = pivot === null || pivot === void 0 ? void 0 : pivot.x) !== null && _l !== void 0 ? _l : anchor.x) + (icon || pixelOffset).x;
|
|
6798
|
+
let y = ((_m = pivot === null || pivot === void 0 ? void 0 : pivot.y) !== null && _m !== void 0 ? _m : anchor.y) + (icon || pixelOffset).y;
|
|
6799
|
+
if (cursorAmount > 0 && !icon) {
|
|
6775
6800
|
// A leader-less label starts centred on its anchor; preserve that box as it lifts away.
|
|
6776
6801
|
if (!normalLeader) {
|
|
6777
6802
|
x -= ele.offsetWidth / layer.coordinates.scaleX / 2;
|
|
@@ -6809,9 +6834,11 @@ var EntityLabel;
|
|
|
6809
6834
|
if (cursorAmount > 0) {
|
|
6810
6835
|
leaderLength += (96 - leaderLength) * cursorAmount;
|
|
6811
6836
|
}
|
|
6837
|
+
// Measured from the ring, so the visible stem is the same length whatever the glyph's size.
|
|
6838
|
+
leaderLength += iconRing;
|
|
6812
6839
|
y = anchorY - leaderLength;
|
|
6813
6840
|
}
|
|
6814
|
-
else if (hover && !reused) {
|
|
6841
|
+
else if (hover && !reused && !icon) {
|
|
6815
6842
|
x = hover.x + pixelOffset.x;
|
|
6816
6843
|
y = hover.y + pixelOffset.y - 24;
|
|
6817
6844
|
}
|
|
@@ -6854,7 +6881,7 @@ var EntityLabel;
|
|
|
6854
6881
|
return null;
|
|
6855
6882
|
}
|
|
6856
6883
|
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 });
|
|
6857
|
-
const opacity = this.prePositioned || MAX_DISTANCE === Infinity ? 1 : 1 - distance / MAX_DISTANCE;
|
|
6884
|
+
const opacity = this.prePositioned || hoverOnly || MAX_DISTANCE === Infinity ? 1 : 1 - distance / MAX_DISTANCE;
|
|
6858
6885
|
return {
|
|
6859
6886
|
canFlip: leader && presentation !== "icon", hasLeader: leader,
|
|
6860
6887
|
textWrapped: ((sourceNaturalText === null || sourceNaturalText === void 0 ? void 0 : sourceNaturalText.offsetWidth) || 0) > TEXT_MAX_WIDTH,
|
|
@@ -6863,6 +6890,7 @@ var EntityLabel;
|
|
|
6863
6890
|
viewportWidth: this.viewer.canvas.clientWidth,
|
|
6864
6891
|
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
6892
|
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,
|
|
6893
|
+
iconRadius: icon === null || icon === void 0 ? void 0 : icon.radius,
|
|
6866
6894
|
// Priority shows the hovered member individually without dragging its cluster along.
|
|
6867
6895
|
opacity, priority: hover || cursorAmount > 0 || (state === null || state === void 0 ? void 0 : state.highlighted) ? 1 : 0, options: this.options, text: originalText, clusterBounds
|
|
6868
6896
|
};
|
|
@@ -6870,7 +6898,7 @@ var EntityLabel;
|
|
|
6870
6898
|
let displacement = { x: 0, y: 0 };
|
|
6871
6899
|
let nudge = { x: 0, y: 0, fromX: 0, fromY: 0, targetX: 0, targetY: 0, start: 0 };
|
|
6872
6900
|
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;
|
|
6901
|
+
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
6902
|
const show = (placement === null || placement === void 0 ? void 0 : placement.visible) && placement.opacity > 0;
|
|
6875
6903
|
clickEntityIds = show ? placement.entityIds : [];
|
|
6876
6904
|
ele.style.visibility = show ? "visible" : "hidden";
|
|
@@ -6907,6 +6935,29 @@ var EntityLabel;
|
|
|
6907
6935
|
this.viewer.scene.requestRender();
|
|
6908
6936
|
}
|
|
6909
6937
|
fitIconBackground === null || fitIconBackground === void 0 ? void 0 : fitIconBackground();
|
|
6938
|
+
const stack = JSON.stringify(placement.icons || []);
|
|
6939
|
+
if (iconStack && stack !== displayedStack) {
|
|
6940
|
+
displayedStack = stack;
|
|
6941
|
+
const looks = ((_b = placement.icons) === null || _b === void 0 ? void 0 : _b.length) ? [iconLook(this.options), ...placement.icons] : [];
|
|
6942
|
+
// One small size for all, so no icon in the arrangement reads as more important than another.
|
|
6943
|
+
const size = (this.options.iconSize || 24) * ((_c = this.options.iconScale) !== null && _c !== void 0 ? _c : 1) * ICON_STACK_SCALE;
|
|
6944
|
+
const built = looks.map(look => this.buildIcon({ ...look, iconSize: size }, counter));
|
|
6945
|
+
// Two sit side by side; three make a triangle with the representative on top.
|
|
6946
|
+
iconStack.style.gridTemplateColumns = built.length === 3 ? "auto auto" : `repeat(${built.length}, auto)`;
|
|
6947
|
+
if (built.length === 3) {
|
|
6948
|
+
built[0].icon.style.gridColumn = "1 / span 2";
|
|
6949
|
+
}
|
|
6950
|
+
iconStack.replaceChildren(...built.map(({ icon }) => icon));
|
|
6951
|
+
iconStack.style.display = built.length ? "inline-grid" : "none";
|
|
6952
|
+
// The glyph stays measurable, since cluster membership is taken from its footprint.
|
|
6953
|
+
iconElement.style.visibility = built.length ? "hidden" : "";
|
|
6954
|
+
iconElement.style.position = built.length ? "absolute" : "relative";
|
|
6955
|
+
stackedFits = built.map(({ fit }) => fit).filter(Boolean);
|
|
6956
|
+
// The stack widens the label, which the next frame has to measure.
|
|
6957
|
+
this.viewer.scene.requestRender();
|
|
6958
|
+
}
|
|
6959
|
+
for (const fit of stackedFits)
|
|
6960
|
+
fit();
|
|
6910
6961
|
if (iconContainer) {
|
|
6911
6962
|
const badgeWidth = countElement.offsetWidth;
|
|
6912
6963
|
const iconWidth = iconElement.offsetWidth;
|
|
@@ -6922,36 +6973,43 @@ var EntityLabel;
|
|
|
6922
6973
|
// Summary and badge changes must fit on their first visible frame, including after resize.
|
|
6923
6974
|
const ring = this.options.anchorRing;
|
|
6924
6975
|
const pointer = (layer.pointer || (cursorMotion.target ? cursorMotion.position : undefined) || (this.Transient && !this.Persistent ?
|
|
6925
|
-
(this.hoverFade.to === 0 ? this.retainedHoverPosition : (
|
|
6926
|
-
const
|
|
6927
|
-
const
|
|
6976
|
+
(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));
|
|
6977
|
+
const iconRing = frame.iconRadius ? Math.max(ICON_RING_MIN, frame.iconRadius + ICON_RING_PADDING) : 0;
|
|
6978
|
+
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);
|
|
6979
|
+
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
6980
|
const targetRadius = normalRadius + (15.4 - normalRadius) * cursorMotion.amount;
|
|
6981
|
+
// Around a glyph the ring keeps the glyph's size and only fades its stroke in, so it never covers the icon.
|
|
6982
|
+
const targetOuter = iconRing || targetRadius || 2.5;
|
|
6983
|
+
const targetInner = iconRing ? (targetRadius > 0 ? iconRing - 2 : iconRing) : Math.max(0, targetRadius - 2);
|
|
6929
6984
|
const now = Date.now();
|
|
6930
|
-
const duration = (
|
|
6985
|
+
const duration = (_l = ring === null || ring === void 0 ? void 0 : ring.transitionDuration) !== null && _l !== void 0 ? _l : 200;
|
|
6931
6986
|
const sharedRing = this.Transient && !this.Persistent && this.hoverFade.to === 1 ? this.hoverRingState : undefined;
|
|
6932
6987
|
let ringAnimation = sharedRing ? sharedRing.animation : this.ringAnimation;
|
|
6933
6988
|
if (!ringAnimation) {
|
|
6934
|
-
|
|
6989
|
+
const outer = iconRing || 2.5;
|
|
6990
|
+
const inner = iconRing;
|
|
6991
|
+
ringAnimation = { target: outer, targetInner: inner, start: now, outer, inner, fromOuter: outer, fromInner: inner };
|
|
6935
6992
|
}
|
|
6936
6993
|
const animateRing = () => {
|
|
6937
6994
|
const progress = duration > 0 ? Math.min(1, Math.max(0, (now - ringAnimation.start) / duration)) : 1;
|
|
6938
6995
|
const eased = progress * progress * (3 - 2 * progress);
|
|
6939
|
-
ringAnimation.outer = ringAnimation.fromOuter + (
|
|
6940
|
-
ringAnimation.inner = ringAnimation.fromInner + (
|
|
6996
|
+
ringAnimation.outer = ringAnimation.fromOuter + (ringAnimation.target - ringAnimation.fromOuter) * eased;
|
|
6997
|
+
ringAnimation.inner = ringAnimation.fromInner + (ringAnimation.targetInner - ringAnimation.fromInner) * eased;
|
|
6941
6998
|
return progress;
|
|
6942
6999
|
};
|
|
6943
7000
|
animateRing();
|
|
6944
|
-
if (ringAnimation.target !==
|
|
7001
|
+
if (ringAnimation.target !== targetOuter || ringAnimation.targetInner !== targetInner) {
|
|
6945
7002
|
ringAnimation = {
|
|
6946
7003
|
...ringAnimation,
|
|
6947
|
-
target:
|
|
7004
|
+
target: targetOuter,
|
|
7005
|
+
targetInner,
|
|
6948
7006
|
start: now,
|
|
6949
7007
|
fromOuter: ringAnimation.outer,
|
|
6950
7008
|
fromInner: ringAnimation.inner
|
|
6951
7009
|
};
|
|
6952
7010
|
}
|
|
6953
7011
|
// Animate the hole and stem together; no CSS transition may lag behind a moving world anchor.
|
|
6954
|
-
if (animateRing() < 1 && (ringAnimation.fromOuter !==
|
|
7012
|
+
if (animateRing() < 1 && (ringAnimation.fromOuter !== targetOuter || ringAnimation.fromInner !== targetInner)) {
|
|
6955
7013
|
this.viewer.scene.requestRender();
|
|
6956
7014
|
}
|
|
6957
7015
|
this.ringAnimation = ringAnimation;
|
|
@@ -6966,19 +7024,19 @@ var EntityLabel;
|
|
|
6966
7024
|
if (leader && angled) {
|
|
6967
7025
|
// The declutter owns the side; the fit only says which one had the room to begin with.
|
|
6968
7026
|
const run = Math.max(ANGLED_LEADER_RUN, radius + 4);
|
|
6969
|
-
const side = (
|
|
7027
|
+
const side = (_o = (_m = placement.textSide) !== null && _m !== void 0 ? _m : frame.leaderSide) !== null && _o !== void 0 ? _o : "right";
|
|
6970
7028
|
const beside = side === "left" ? frame.anchorX - run - width : frame.anchorX + run;
|
|
6971
7029
|
position.x = Math.max(0, Math.min(beside, this.viewer.canvas.clientWidth - width));
|
|
6972
7030
|
}
|
|
6973
7031
|
else if (leader && placement.textSide === "left") {
|
|
6974
7032
|
position.x = Math.max(0, Math.min(frame.anchorX - width, this.viewer.canvas.clientWidth - width));
|
|
6975
7033
|
}
|
|
6976
|
-
const gap = (
|
|
7034
|
+
const gap = (_q = (_p = this.options.pointerAvoidance) === null || _p === void 0 ? void 0 : _p.gap) !== null && _q !== void 0 ? _q : 12;
|
|
6977
7035
|
const containsPointer = (x, y, margin) => {
|
|
6978
7036
|
return pointer && pointer.x >= x - margin && pointer.x <= x + width + margin && pointer.y >= y - margin && pointer.y <= y + height + margin;
|
|
6979
7037
|
};
|
|
6980
7038
|
const passive = !selectOnClick || !this.visualRegister;
|
|
6981
|
-
if (passive && ((
|
|
7039
|
+
if (passive && ((_r = this.options.pointerAvoidance) === null || _r === void 0 ? void 0 : _r.enabled) !== false && pointer &&
|
|
6982
7040
|
(containsPointer(position.x, position.y, gap) || containsPointer(position.x + displacement.x, position.y + displacement.y, gap))) {
|
|
6983
7041
|
if (containsPointer(position.x + displacement.x, position.y + displacement.y, 0)) {
|
|
6984
7042
|
// Choose against the original box and retain the offset until the pointer leaves both boxes.
|
|
@@ -6996,7 +7054,7 @@ var EntityLabel;
|
|
|
6996
7054
|
else {
|
|
6997
7055
|
displacement = { x: 0, y: 0 };
|
|
6998
7056
|
}
|
|
6999
|
-
const nudgeDuration = (
|
|
7057
|
+
const nudgeDuration = (_t = (_s = this.options.pointerAvoidance) === null || _s === void 0 ? void 0 : _s.transitionDuration) !== null && _t !== void 0 ? _t : 200;
|
|
7000
7058
|
const animateNudge = () => {
|
|
7001
7059
|
const progress = now < nudge.start ? 0 : nudgeDuration > 0 ? Math.min(1, (now - nudge.start) / nudgeDuration) : 1;
|
|
7002
7060
|
const eased = progress * progress * (3 - 2 * progress);
|
|
@@ -7012,7 +7070,7 @@ var EntityLabel;
|
|
|
7012
7070
|
fromY: nudge.y,
|
|
7013
7071
|
targetX: displacement.x,
|
|
7014
7072
|
targetY: displacement.y,
|
|
7015
|
-
start: now + ((
|
|
7073
|
+
start: now + ((_v = (_u = this.options.pointerAvoidance) === null || _u === void 0 ? void 0 : _u.delay) !== null && _v !== void 0 ? _v : 180)
|
|
7016
7074
|
};
|
|
7017
7075
|
}
|
|
7018
7076
|
if (animateNudge() < 1 && (nudge.fromX !== nudge.targetX || nudge.fromY !== nudge.targetY)) {
|
|
@@ -7022,9 +7080,8 @@ var EntityLabel;
|
|
|
7022
7080
|
position.y += nudge.y;
|
|
7023
7081
|
ele.style.left = `${coordinates.x + position.x * coordinates.scaleX}px`;
|
|
7024
7082
|
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}`);
|
|
7083
|
+
for (const clickTarget of Array.from(content.querySelectorAll('[role="button"]'))) {
|
|
7084
|
+
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
7085
|
}
|
|
7029
7086
|
if (leader) {
|
|
7030
7087
|
const nodeRadius = ringAnimation.outer;
|
|
@@ -7064,13 +7121,13 @@ var EntityLabel;
|
|
|
7064
7121
|
// Keep the stem inside the 126-degree arc, away from antialiased endpoints.
|
|
7065
7122
|
const arcFraction = 0.35;
|
|
7066
7123
|
const rotationLimit = Math.PI * arcFraction - Math.PI / 30;
|
|
7067
|
-
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((
|
|
7124
|
+
const targetOffset = hovered ? Math.max(-rotationLimit, Math.min(rotationLimit, wrappedAngle)) : ((_z = ringAnimation.arcOffset) !== null && _z !== void 0 ? _z : 0);
|
|
7068
7125
|
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 - ((
|
|
7126
|
+
const elapsed = Math.min(32, Math.max(0, now - ((_0 = ringAnimation.arcTime) !== null && _0 !== void 0 ? _0 : now)));
|
|
7070
7127
|
const blend = duration > 0 ? 1 - Math.exp(-elapsed / (duration / 3)) : 1;
|
|
7071
7128
|
const approach = (value, target) => Math.abs(value - target) < 0.001 ? target : value + (target - value) * blend;
|
|
7072
|
-
ringAnimation.arcOffset = approach((
|
|
7073
|
-
ringAnimation.arcOpen = approach((
|
|
7129
|
+
ringAnimation.arcOffset = approach((_1 = ringAnimation.arcOffset) !== null && _1 !== void 0 ? _1 : 0, targetOffset);
|
|
7130
|
+
ringAnimation.arcOpen = approach((_2 = ringAnimation.arcOpen) !== null && _2 !== void 0 ? _2 : 0, targetOpen);
|
|
7074
7131
|
ringAnimation.arcTime = now;
|
|
7075
7132
|
if (ringAnimation.arcOffset !== targetOffset || ringAnimation.arcOpen !== targetOpen) {
|
|
7076
7133
|
this.viewer.scene.requestRender();
|
|
@@ -7123,6 +7180,123 @@ var EntityLabel;
|
|
|
7123
7180
|
}, 2500);
|
|
7124
7181
|
});
|
|
7125
7182
|
}
|
|
7183
|
+
/*
|
|
7184
|
+
* Builds one icon glyph from label options, with its background chip when asked for.
|
|
7185
|
+
*
|
|
7186
|
+
* The returned fit squares the chip off once the glyph has a measurable size.
|
|
7187
|
+
*/
|
|
7188
|
+
buildIcon(options, counter) {
|
|
7189
|
+
var _a, _b, _c;
|
|
7190
|
+
let fit;
|
|
7191
|
+
const icon = document.createElement("span");
|
|
7192
|
+
icon.className = "entity-label-icon";
|
|
7193
|
+
icon.style.cssText = `font-size:${(options.iconSize || 24) * ((_a = options.iconScale) !== null && _a !== void 0 ? _a : 1)}px;line-height:1;`;
|
|
7194
|
+
icon.style.textShadow = "0 1px 2px rgba(0, 0, 0, 0.25)";
|
|
7195
|
+
const iconColor = typeof options.iconColor === "string" ? options.iconColor : undefined;
|
|
7196
|
+
const iconBackground = options.iconBackground && options.iconScale !== 0;
|
|
7197
|
+
if (iconColor) {
|
|
7198
|
+
icon.style.color = iconColor;
|
|
7199
|
+
}
|
|
7200
|
+
if (options.iconUrl) {
|
|
7201
|
+
const image = document.createElement("img");
|
|
7202
|
+
image.draggable = false;
|
|
7203
|
+
image.alt = options.icon || "";
|
|
7204
|
+
const scale = (_b = options.iconScale) !== null && _b !== void 0 ? _b : 1;
|
|
7205
|
+
const size = options.iconSize;
|
|
7206
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
7207
|
+
const tint = iconColor ? document.createElementNS(svgNs, "svg") : null;
|
|
7208
|
+
const painted = tint ? document.createElementNS(svgNs, "image") : null;
|
|
7209
|
+
const inked = tint ? document.createElementNS(svgNs, "rect") : null;
|
|
7210
|
+
if (tint) {
|
|
7211
|
+
const maskId = `entity-label-tint-${++tintCounter}`;
|
|
7212
|
+
const mask = document.createElementNS(svgNs, "mask");
|
|
7213
|
+
mask.setAttribute("id", maskId);
|
|
7214
|
+
mask.setAttribute("maskUnits", "userSpaceOnUse");
|
|
7215
|
+
painted.setAttribute("href", options.iconUrl);
|
|
7216
|
+
painted.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
7217
|
+
mask.appendChild(painted);
|
|
7218
|
+
inked.setAttribute("fill", iconColor);
|
|
7219
|
+
inked.setAttribute("mask", `url(#${maskId})`);
|
|
7220
|
+
tint.append(mask, inked);
|
|
7221
|
+
tint.style.display = "block";
|
|
7222
|
+
icon.style.display = "inline-flex";
|
|
7223
|
+
icon.appendChild(tint);
|
|
7224
|
+
}
|
|
7225
|
+
const resize = () => {
|
|
7226
|
+
if (this.disposed || this.counter !== counter) {
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
7229
|
+
const intrinsic = options.iconScale != null && size == null;
|
|
7230
|
+
const width = (intrinsic ? image.naturalWidth || 24 : size || 24) * scale;
|
|
7231
|
+
const height = (intrinsic ? image.naturalHeight || 24 : size || 24) * scale;
|
|
7232
|
+
if (tint) {
|
|
7233
|
+
tint.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
7234
|
+
for (const node of [tint, painted, inked]) {
|
|
7235
|
+
node.setAttribute("width", String(width));
|
|
7236
|
+
node.setAttribute("height", String(height));
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
7239
|
+
else {
|
|
7240
|
+
image.style.width = `${width}px`;
|
|
7241
|
+
image.style.height = `${height}px`;
|
|
7242
|
+
}
|
|
7243
|
+
this.viewer.scene.requestRender();
|
|
7244
|
+
};
|
|
7245
|
+
image.onload = resize;
|
|
7246
|
+
resize();
|
|
7247
|
+
image.src = options.iconUrl;
|
|
7248
|
+
if (!tint) {
|
|
7249
|
+
icon.appendChild(image);
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
else if (typeof options.iconClass === "string" && options.iconClass) {
|
|
7253
|
+
icon.className = `entity-label-icon ${options.iconClass}`;
|
|
7254
|
+
}
|
|
7255
|
+
else {
|
|
7256
|
+
icon.textContent = options.icon || "●";
|
|
7257
|
+
}
|
|
7258
|
+
if (iconBackground) {
|
|
7259
|
+
const color = Color.fromCssColorString(iconColor || "white") || Color.WHITE;
|
|
7260
|
+
const luminance = 0.2126 * color.red + 0.7152 * color.green + 0.0722 * color.blue;
|
|
7261
|
+
const background = (luminance > 0.5 ? color.darken(ICON_BACKGROUND_BLEND, new Color()) :
|
|
7262
|
+
color.brighten(ICON_BACKGROUND_BLEND, new Color()));
|
|
7263
|
+
const size = (options.iconSize || 24) * ((_c = options.iconScale) !== null && _c !== void 0 ? _c : 1);
|
|
7264
|
+
icon.style.backgroundColor = background.withAlpha(ICON_BACKGROUND_ALPHA).toCssColorString();
|
|
7265
|
+
icon.style.borderRadius = "50%";
|
|
7266
|
+
icon.style.padding = `${size / 3}px`;
|
|
7267
|
+
icon.style.display = "inline-flex";
|
|
7268
|
+
icon.style.alignItems = "center";
|
|
7269
|
+
icon.style.justifyContent = "center";
|
|
7270
|
+
icon.style.minWidth = `${size}px`;
|
|
7271
|
+
icon.style.minHeight = `${size}px`;
|
|
7272
|
+
icon.style.boxSizing = "content-box";
|
|
7273
|
+
let fitted = false;
|
|
7274
|
+
fit = () => {
|
|
7275
|
+
if (fitted) {
|
|
7276
|
+
return;
|
|
7277
|
+
}
|
|
7278
|
+
const padding = size / 3;
|
|
7279
|
+
const width = icon.offsetWidth - padding * 2;
|
|
7280
|
+
const height = icon.offsetHeight - padding * 2;
|
|
7281
|
+
if (width <= 0 || height <= 0) {
|
|
7282
|
+
return;
|
|
7283
|
+
}
|
|
7284
|
+
fitted = true;
|
|
7285
|
+
const longest = Math.max(width, height);
|
|
7286
|
+
const difference = (longest - Math.min(width, height)) / longest;
|
|
7287
|
+
if (difference > ICON_BACKGROUND_UNIFORM_TOLERANCE) {
|
|
7288
|
+
return;
|
|
7289
|
+
}
|
|
7290
|
+
icon.style.minWidth = `${longest}px`;
|
|
7291
|
+
icon.style.minHeight = `${longest}px`;
|
|
7292
|
+
this.viewer.scene.requestRender();
|
|
7293
|
+
};
|
|
7294
|
+
}
|
|
7295
|
+
if (options.iconScale === 0) {
|
|
7296
|
+
icon.style.display = "none";
|
|
7297
|
+
}
|
|
7298
|
+
return { icon, fit };
|
|
7299
|
+
}
|
|
7126
7300
|
/**
|
|
7127
7301
|
* Removes label from the viewer and unsubscribes from events.
|
|
7128
7302
|
*/
|
|
@@ -50400,7 +50574,7 @@ var StyleUtils;
|
|
|
50400
50574
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
50401
50575
|
})(StyleUtils || (StyleUtils = {}));
|
|
50402
50576
|
|
|
50403
|
-
const VERSION = "7.4.
|
|
50577
|
+
const VERSION = "7.4.5";
|
|
50404
50578
|
/**
|
|
50405
50579
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
50406
50580
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|