bruce-cesium 6.9.1 → 6.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import * as Cesium from 'cesium';
2
- import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, DistanceDisplayCondition, HeightReference, ColorBlendMode, HeadingPitchRoll, Math as Math$1, Transforms, ShadowMode, Cartesian3, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ConstantPositionProperty, PolygonHierarchy, PolylineGraphics, ArcType, CornerType, JulianDate, Quaternion, Matrix4, SceneTransforms, NearFarScalar, Cartesian2, Matrix3, Rectangle, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, CesiumInspector, ClockRange, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, ScreenSpaceEventHandler, ScreenSpaceEventType, BoundingSphere, GeometryInstance, Fullscreen, Intersect, CzmlDataSource } from 'cesium';
3
- import { Cartes, Entity as Entity$1, ENVIRONMENT, Calculator, ClientFile, EntityLod, EntityTag, EntityType, LRUCache, ObjectUtils, Style, Api, Bounds, Geometry, Carto, BruceEvent, EntityCoords, MenuItem, Tileset, ProjectView, ProjectViewBookmark, ZoomControl, DataLab, DelayQueue, EntityHistoricData, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, ProgramKey, EntitySource, ProjectViewLegacyTile, ProjectViewTile, Camera, Session, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType } from 'bruce-models';
2
+ import { Cartographic, Entity, DistanceDisplayCondition, ColorMaterialProperty, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, HeightReference, ColorBlendMode, HeadingPitchRoll, Math as Math$1, Transforms, ShadowMode, Cartesian3, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ConstantPositionProperty, ArcType, CornerType, JulianDate, Quaternion, Matrix4, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Cartesian2, SceneTransforms, NearFarScalar, Matrix3, Rectangle, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileset, Cesium3DTileColorBlendMode, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, PolygonPipeline, CesiumInspector, ClockRange, BoundingSphere, GeometryInstance, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, Intersect, CzmlDataSource } from 'cesium';
3
+ import { Cartes, Entity as Entity$1, ENVIRONMENT, Calculator, ClientFile, EntityLod, EntityTag, EntityType, LRUCache, ObjectUtils, Style, Api, Carto, Geometry, Bounds, Color as Color$1, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DataLab, DelayQueue, EntityHistoricData, BruceApi, EntityRelation, AccountConcept, RecordChangeFeed, ProgramKey, EntitySource, ProjectViewLegacyTile, ProjectViewTile, Camera, Session, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType } from 'bruce-models';
4
4
 
5
5
  /**
6
6
  * Ensures a number is returned from a given value.
@@ -2607,7 +2607,9 @@ var Widget;
2607
2607
  constructor(params) {
2608
2608
  this.widgetId = ObjectUtils.UId();
2609
2609
  let { viewer, container, manager } = params;
2610
- if (!container) {
2610
+ // A host app can pass an undefined viewer (eg. mid-teardown); fall back to
2611
+ // no container rather than crashing on viewer.container.
2612
+ if (!container && viewer) {
2611
2613
  container = viewer.container;
2612
2614
  }
2613
2615
  this._viewer = viewer;
@@ -3164,7 +3166,10 @@ class WidgetViewBar extends Widget.AWidget {
3164
3166
  this.customControls = new Map();
3165
3167
  this._generateStyles();
3166
3168
  this._generateElement();
3167
- this._viewer[VIEWER_VIEW_BAR_WIDGET_KEY] = this;
3169
+ // Guard against a host app constructing this widget with no live viewer.
3170
+ if (this._viewer) {
3171
+ this._viewer[VIEWER_VIEW_BAR_WIDGET_KEY] = this;
3172
+ }
3168
3173
  }
3169
3174
  Dispose() {
3170
3175
  super.Dispose();
@@ -23429,7 +23434,10 @@ class WidgetLeftPanel extends Widget.AWidget {
23429
23434
  this._viewId = params.viewId;
23430
23435
  this._generateStyles();
23431
23436
  this._generateElement();
23432
- this._viewer[VIEWER_LEFT_PANEL_WIDGET_KEY] = this;
23437
+ // Guard against a host app constructing this widget with no live viewer.
23438
+ if (this._viewer) {
23439
+ this._viewer[VIEWER_LEFT_PANEL_WIDGET_KEY] = this;
23440
+ }
23433
23441
  this._loading = this.loadBookmarks();
23434
23442
  this._loading.then(() => {
23435
23443
  if (params.runFirstBookmark && this.bookmarks.length) {
@@ -23871,10 +23879,18 @@ class WidgetLeftPanel extends Widget.AWidget {
23871
23879
  return;
23872
23880
  }
23873
23881
  const clazz = this.customTabs.get(this._enabledPanelTab);
23874
- tabContent = new clazz({
23875
- widget: this,
23876
- container: container
23877
- });
23882
+ try {
23883
+ tabContent = new clazz({
23884
+ widget: this,
23885
+ container: container
23886
+ });
23887
+ }
23888
+ catch (e) {
23889
+ // Partner-supplied tab content class; a throwing constructor shouldn't take
23890
+ // down the whole panel.
23891
+ console.error(e);
23892
+ return;
23893
+ }
23878
23894
  break;
23879
23895
  }
23880
23896
  this._enabledTabContent = tabContent;
@@ -23896,17 +23912,18 @@ class WidgetLeftPanel extends Widget.AWidget {
23896
23912
  document.documentElement.style.setProperty(VIEWER_LEFT_PANEL_CSS_VAR_LEFT, "0px");
23897
23913
  }
23898
23914
  SelectBookmark(bookmark) {
23915
+ var _a;
23899
23916
  const isFirstEnabled = !this._lastEnabledBookmarkId;
23900
23917
  this._lastEnabledBookmarkId = bookmark.ID;
23901
23918
  ViewRenderEngine.Render({
23902
- apiGetter: this._apiGetters.GetBruceGetter(),
23919
+ apiGetter: (_a = this._apiGetters) === null || _a === void 0 ? void 0 : _a.GetBruceGetter(),
23903
23920
  bookmark: bookmark,
23904
23921
  bookmarkId: bookmark.ID,
23905
23922
  manager: this._manager,
23906
23923
  skipTransition: isFirstEnabled,
23907
23924
  viewer: this._viewer,
23908
23925
  viewId: this._viewId
23909
- });
23926
+ }).catch((e) => console.error(e));
23910
23927
  if (this._onBookmarkSelect) {
23911
23928
  this._onBookmarkSelect.Trigger(bookmark);
23912
23929
  }
@@ -26608,7 +26625,10 @@ class WidgetBookmarks extends Widget.AWidget {
26608
26625
  }
26609
26626
  this._updateBookmarks();
26610
26627
  });
26611
- this._viewer[VIEWER_BOOKMARKS_WIDGET_KEY] = this;
26628
+ // Guard against a host app constructing this widget with no live viewer.
26629
+ if (this._viewer) {
26630
+ this._viewer[VIEWER_BOOKMARKS_WIDGET_KEY] = this;
26631
+ }
26612
26632
  }
26613
26633
  LoadViewId(params) {
26614
26634
  let { viewId, runFirstBookmark, autoPlay, bookmarkId } = params;
@@ -26986,9 +27006,10 @@ class WidgetBookmarks extends Widget.AWidget {
26986
27006
  `;
26987
27007
  }
26988
27008
  _updateBookmarks() {
27009
+ var _a;
26989
27010
  const bookmarks = this.bookmarks;
26990
27011
  this._element.style.display = bookmarks.length ? "flex" : "none";
26991
- const api = this._apiGetters.GetBruceApi();
27012
+ const api = (_a = this._apiGetters) === null || _a === void 0 ? void 0 : _a.GetBruceApi();
26992
27013
  const row = this._row;
26993
27014
  row.innerHTML = "";
26994
27015
  for (const bookmark of bookmarks) {
@@ -27030,7 +27051,7 @@ class WidgetBookmarks extends Widget.AWidget {
27030
27051
  skipTransition: isFirstEnabled,
27031
27052
  viewId: this._viewId,
27032
27053
  viewer: this._viewer
27033
- });
27054
+ }).catch((e) => console.error(e));
27034
27055
  }
27035
27056
  _updateBookmark() {
27036
27057
  const allBookmarks = this._row.querySelectorAll(".NextspaceBookmarksRowItem");
@@ -29116,7 +29137,12 @@ class WidgetCursorBar extends Widget.AWidget {
29116
29137
  this._cesiumEventRemoval = null;
29117
29138
  }
29118
29139
  _listenSelection() {
29140
+ var _a, _b;
29119
29141
  this._disposeCesiumEvent();
29142
+ // No live viewer/scene to attach cursor listeners to (eg. widget constructed without one).
29143
+ if (!((_b = (_a = this._viewer) === null || _a === void 0 ? void 0 : _a.scene) === null || _b === void 0 ? void 0 : _b.canvas)) {
29144
+ return;
29145
+ }
29120
29146
  const events = new ScreenSpaceEventHandler(this._viewer.scene.canvas);
29121
29147
  const throttle = new CursorBarMouseEventThrottle(this._viewer);
29122
29148
  let lastHoverPos = null;
@@ -36638,7 +36664,7 @@ function getHeightRef$2(style, defaultStyle) {
36638
36664
 
36639
36665
  var EntityRenderEnginePolygon;
36640
36666
  (function (EntityRenderEnginePolygon) {
36641
- function Render(params) {
36667
+ async function Render(params) {
36642
36668
  var _a, _b;
36643
36669
  const entity = params.entity;
36644
36670
  const pRings = Entity$1.GetValue({
@@ -36649,9 +36675,26 @@ var EntityRenderEnginePolygon;
36649
36675
  return null;
36650
36676
  }
36651
36677
  const style = params.style;
36678
+ const fillType = style.fillType || Style.EPolygonFillType.Color;
36652
36679
  const fillColorTrace = style.fillColor ? Calculator.TraceGetColor(style.fillColor, entity, params.tags) : { value: null, effective: null };
36653
36680
  const bFillColor = fillColorTrace.value;
36654
36681
  const cFillColor = bFillColor ? ColorToCColor(bFillColor) : Color.fromCssColorString("rgba(139, 195, 74, 0.8)");
36682
+ let textureDataUri = null;
36683
+ let textureTraceEffective = null;
36684
+ if (fillType === Style.EPolygonFillType.Texture) {
36685
+ const resolved = await resolveTexturedFill({
36686
+ api: params.api,
36687
+ style,
36688
+ entity,
36689
+ tags: params.tags
36690
+ });
36691
+ textureDataUri = resolved.dataUri;
36692
+ textureTraceEffective = resolved.effective;
36693
+ }
36694
+ const hasFill = fillType === Style.EPolygonFillType.Texture ? Boolean(textureDataUri) : cFillColor.alpha > 0;
36695
+ const fillMaterial = textureDataUri
36696
+ ? new ImageMaterialProperty({ image: textureDataUri, transparent: true })
36697
+ : cFillColor;
36655
36698
  const lineColorTrace = style.lineColor ? Calculator.TraceGetColor(style.lineColor, entity, params.tags) : { value: null, effective: null };
36656
36699
  const bLineColor = lineColorTrace.value;
36657
36700
  const cLineColor = bLineColor ? ColorToCColor(bLineColor) : Color.fromCssColorString("rgba(80, 80, 80, 0.8)");
@@ -36670,7 +36713,7 @@ var EntityRenderEnginePolygon;
36670
36713
  }
36671
36714
  // If both outline and fill is not available then don't render anything.
36672
36715
  if ((width <= 0 || cLineColor.alpha <= 0) &&
36673
- cFillColor.alpha <= 0) {
36716
+ !hasFill) {
36674
36717
  return null;
36675
36718
  }
36676
36719
  let heightRef = getHeightRef$3(style);
@@ -36725,7 +36768,7 @@ var EntityRenderEnginePolygon;
36725
36768
  id: ObjectUtils.UId(15),
36726
36769
  polygon: {
36727
36770
  hierarchy: new PolygonHierarchy(posses, holePosses.map(x => new PolygonHierarchy(x))),
36728
- material: cFillColor,
36771
+ material: fillMaterial,
36729
36772
  extrudedHeight: extrusion.value,
36730
36773
  extrudedHeightReference: extrusion.exHeightRef,
36731
36774
  shadows: ShadowMode.ENABLED,
@@ -36790,15 +36833,21 @@ var EntityRenderEnginePolygon;
36790
36833
  cEntity.polygon.distanceDisplayCondition = new ConstantProperty(EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance, width <= 0 || !cLineColor || units == "m" ? size : null, true));
36791
36834
  cEntity.polygon.shadows = new ConstantProperty(ShadowMode.ENABLED);
36792
36835
  cEntity.polygon.classificationType = new ConstantProperty(classification);
36793
- // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
36794
- // WARNING: polygon does not support animation (yet?).
36795
- CesiumEntityStyler.SetDefaultColor({
36796
- color: cFillColor,
36797
- entity: cEntity,
36798
- viewer: params.viewer,
36799
- override: true,
36800
- requestRender: false
36801
- });
36836
+ // TODO: animate the texture!
36837
+ if (textureDataUri) {
36838
+ cEntity.polygon.material = fillMaterial;
36839
+ }
36840
+ else {
36841
+ // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
36842
+ // WARNING: polygon does not support animation (yet?).
36843
+ CesiumEntityStyler.SetDefaultColor({
36844
+ color: cFillColor,
36845
+ entity: cEntity,
36846
+ viewer: params.viewer,
36847
+ override: true,
36848
+ requestRender: false
36849
+ });
36850
+ }
36802
36851
  cEntity.show = true;
36803
36852
  }
36804
36853
  if (hasOutline) {
@@ -36946,6 +36995,7 @@ var EntityRenderEnginePolygon;
36946
36995
  }
36947
36996
  cEntity.styleEffective = StyleEffective.Combine([
36948
36997
  { key: "color", effective: fillColorTrace.effective },
36998
+ { key: "texture", effective: textureTraceEffective },
36949
36999
  { key: "lineColor", effective: lineColorTrace.effective },
36950
37000
  { key: "lineWidth", effective: lineWidthTrace.effective }
36951
37001
  ]);
@@ -36997,11 +37047,12 @@ var EntityRenderEnginePolygon;
36997
37047
  }
36998
37048
  }
36999
37049
  const pStyle = (_b = style === null || style === void 0 ? void 0 : style.polygonStyle) !== null && _b !== void 0 ? _b : {};
37000
- const cEntity = Render({
37050
+ const cEntity = await Render({
37001
37051
  entity: entity,
37002
37052
  style: pStyle,
37003
37053
  tags: tags,
37004
37054
  viewer: params.viewer,
37055
+ api,
37005
37056
  maxDistance: zoomItem.MaxZoom,
37006
37057
  minDistance: zoomItem.MinZoom,
37007
37058
  // Temporarily disabling re-using graphics for polygons as they have some bugs, and
@@ -37119,6 +37170,95 @@ async function getStyle$4(api, entity, styleId) {
37119
37170
  }
37120
37171
  return style;
37121
37172
  }
37173
+ // Cache of tinted texture data URIs, keyed by resolved url + color mask, so repeated renders of the
37174
+ // same polygon (or multiple polygons sharing a texture) don't refetch/reprocess the same image.
37175
+ const _textureCache = new LRUCache(50);
37176
+ /**
37177
+ * Returns if a resolved texture value looks like a URL rather than a client file ID.
37178
+ * @param value
37179
+ */
37180
+ function looksLikeTextureUrl(value) {
37181
+ return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value) || value.startsWith("//") || value.startsWith("data:");
37182
+ }
37183
+ /**
37184
+ * Resolves a polygon style's texture field and if a color ask is needed it tints the resulting image.
37185
+ * @param params
37186
+ */
37187
+ async function resolveTexturedFill(params) {
37188
+ const { api, style, entity, tags } = params;
37189
+ const textureTrace = style.texture ? Calculator.TraceGetString(style.texture, entity, tags) : { value: null, effective: null };
37190
+ const raw = textureTrace.value;
37191
+ if (!raw || typeof raw != "string" || !api) {
37192
+ return { dataUri: null, effective: textureTrace.effective };
37193
+ }
37194
+ let url = raw;
37195
+ if (!looksLikeTextureUrl(raw)) {
37196
+ await api.Loading;
37197
+ url = ClientFile.GetUrl({
37198
+ api,
37199
+ fileId: raw,
37200
+ viaCdn: true
37201
+ });
37202
+ }
37203
+ const mask = style.textureColorMask;
37204
+ const cacheKey = "texture-" + url + "-" + (mask ? mask.type + "-" + mask.minColor + "-" + mask.maxColor : "none");
37205
+ let prom = _textureCache.Get(cacheKey);
37206
+ if (!prom) {
37207
+ prom = buildTintedTextureDataUri(url, mask).catch(() => null);
37208
+ _textureCache.Set(cacheKey, prom);
37209
+ }
37210
+ return { dataUri: await prom, effective: textureTrace.effective };
37211
+ }
37212
+ /**
37213
+ * Fetches an image and, if a color mask is provided, remaps its (assumed grayscale) pixel values
37214
+ * into a gradient between the mask's minColor/maxColor, preserving source alpha.
37215
+ * @param url
37216
+ * @param mask
37217
+ */
37218
+ async function buildTintedTextureDataUri(url, mask) {
37219
+ const response = await fetch(url);
37220
+ const blob = await response.blob();
37221
+ const objectUrl = URL.createObjectURL(blob);
37222
+ let image;
37223
+ try {
37224
+ image = await loadImage(objectUrl);
37225
+ }
37226
+ finally {
37227
+ URL.revokeObjectURL(objectUrl);
37228
+ }
37229
+ const canvas = document.createElement("canvas");
37230
+ canvas.width = image.width;
37231
+ canvas.height = image.height;
37232
+ const context = canvas.getContext("2d");
37233
+ context.drawImage(image, 0, 0);
37234
+ if (mask && mask.type === Style.ETextureColorMaskType.BlackWhite) {
37235
+ const minColor = Color$1.ColorFromStr(mask.minColor) || { red: 0, green: 0, blue: 0, alpha: 1 };
37236
+ const maxColor = Color$1.ColorFromStr(mask.maxColor) || { red: 255, green: 255, blue: 255, alpha: 1 };
37237
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
37238
+ const data = imageData.data;
37239
+ for (let i = 0; i < data.length; i += 4) {
37240
+ // The texture is rendered black-to-white server-side, so any channel carries the value.
37241
+ const t = data[i] / 255;
37242
+ data[i] = Math.round(minColor.red + (maxColor.red - minColor.red) * t);
37243
+ data[i + 1] = Math.round(minColor.green + (maxColor.green - minColor.green) * t);
37244
+ data[i + 2] = Math.round(minColor.blue + (maxColor.blue - minColor.blue) * t);
37245
+ // Preserve source transparency (eg unrasterized pixels) blended with the mask's own alpha.
37246
+ const srcAlpha = data[i + 3] / 255;
37247
+ const maskAlpha = minColor.alpha + (maxColor.alpha - minColor.alpha) * t;
37248
+ data[i + 3] = Math.round(srcAlpha * maskAlpha * 255);
37249
+ }
37250
+ context.putImageData(imageData, 0, 0);
37251
+ }
37252
+ return canvas.toDataURL("image/png");
37253
+ }
37254
+ function loadImage(src) {
37255
+ return new Promise((res, rej) => {
37256
+ const image = new Image();
37257
+ image.onload = () => res(image);
37258
+ image.onerror = (e) => rej(e);
37259
+ image.src = src;
37260
+ });
37261
+ }
37122
37262
  /**
37123
37263
  * Compares two color materials.
37124
37264
  * Returns if they are equal.
@@ -38419,7 +38559,7 @@ var StyleUtils;
38419
38559
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
38420
38560
  })(StyleUtils || (StyleUtils = {}));
38421
38561
 
38422
- const VERSION = "6.9.1";
38562
+ const VERSION = "6.9.3";
38423
38563
  /**
38424
38564
  * Updates the environment instance used by bruce-cesium to one specified.
38425
38565
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.