bruce-cesium 2.1.8 → 2.1.9

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 { BruceEvent, Cartes, Carto, Entity as Entity$1, Geometry, Tileset, MathUtils, LRUCache, ZoomControl, Style, EntityTag, Calculator, EntityLod, EntityType, ClientFile, ObjectUtils, DelayQueue, BatchedDataGetter, EntityRelationType, EntityCoords, EntityFilterGetter, EntitySource, MenuItem, EntityRelation, ENVIRONMENT, ProjectView, ProjectViewBookmark, ProjectViewTile, ProjectViewLegacyTile, ProgramKey, Camera } from 'bruce-models';
2
2
  import * as Cesium from 'cesium';
3
- import { Cartesian2, Cartographic, CallbackProperty, Cartesian3, Color, Rectangle, Math as Math$1, Entity, Primitive, Cesium3DTileFeature, SceneMode, HeightReference, DistanceDisplayCondition, NearFarScalar, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, Cesium3DTileColorBlendMode, HeadingPitchRange, createOsmBuildings, Cesium3DTileStyle, KmlDataSource, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, CesiumInspector, OrthographicFrustum, JulianDate, Cesium3DTileset, Matrix4, Matrix3, IonResource, EllipsoidGeodesic, sampleTerrainMostDetailed, ColorMaterialProperty, EasingFunction, GeometryInstance, PolygonPipeline } from 'cesium';
3
+ import { Cartesian2, Cartographic, CallbackProperty, Cartesian3, Color, Rectangle, Math as Math$1, Entity, Primitive, Cesium3DTileFeature, HeightReference, DistanceDisplayCondition, NearFarScalar, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, SceneMode, HeadingPitchRange, Cesium3DTileColorBlendMode, createOsmBuildings, Cesium3DTileStyle, KmlDataSource, OrthographicFrustum, JulianDate, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, Cesium3DTileset, Matrix4, Matrix3, IonResource, CesiumInspector, EllipsoidGeodesic, sampleTerrainMostDetailed, PolygonPipeline, ColorMaterialProperty, EasingFunction, GeometryInstance } from 'cesium';
4
4
 
5
5
  var TIME_LAG = 300;
6
6
  var POSITION_CHECK_TIMER = 950;
@@ -2713,6 +2713,167 @@ var Quad = /** @class */ (function () {
2713
2713
  };
2714
2714
  return Quad;
2715
2715
  }());
2716
+ var _clusterImageCache = new LRUCache(500);
2717
+ var _clusterImageLoadedCache = new LRUCache(500);
2718
+ function _loadClusterImage(params) {
2719
+ return __awaiter(this, void 0, void 0, function () {
2720
+ var size, txtColor, bgColor, text, iconUrl, key, cacheData, prom;
2721
+ return __generator(this, function (_a) {
2722
+ switch (_a.label) {
2723
+ case 0:
2724
+ size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
2725
+ key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
2726
+ cacheData = _clusterImageCache.Get(key);
2727
+ if (!cacheData) return [3 /*break*/, 2];
2728
+ return [4 /*yield*/, cacheData];
2729
+ case 1: return [2 /*return*/, _a.sent()];
2730
+ case 2:
2731
+ prom = new Promise(function (res, rej) {
2732
+ var canvas = document.createElement("canvas");
2733
+ canvas.width = size;
2734
+ canvas.height = size;
2735
+ var ctx = canvas.getContext("2d");
2736
+ var drawWithoutImage = function (img) {
2737
+ ctx.beginPath();
2738
+ ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, false);
2739
+ var fill = null;
2740
+ var txt = null;
2741
+ if (img) {
2742
+ var brightness = calculateImageBrightness(img);
2743
+ // brightness < 128 = light background.
2744
+ fill = brightness < 128 ? "white" : "#114d78";
2745
+ txt = brightness < 128 ? "black" : "white";
2746
+ }
2747
+ else {
2748
+ fill = bgColor ? bgColor : "#114d78";
2749
+ txt = txtColor ? txtColor : "white";
2750
+ }
2751
+ ctx.fillStyle = fill;
2752
+ ctx.fill();
2753
+ var maxTextWidth = size * 0.8;
2754
+ var maxTextHeight = size * 0.8;
2755
+ var minTextSize = Math.floor(size / 10);
2756
+ var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
2757
+ ctx.font = "bold ".concat(textSize, "px Arial");
2758
+ ctx.fillStyle = txt;
2759
+ ctx.textAlign = "center";
2760
+ ctx.textBaseline = "middle";
2761
+ ctx.fillText(text, size / 2, size / 2);
2762
+ };
2763
+ var drawWithImage = function (img) {
2764
+ var aspectRatio = img.width / img.height;
2765
+ var imageSize = Math.min(size / 2, img.width, img.height);
2766
+ if (imageSize / aspectRatio > size / 2) {
2767
+ imageSize = (size / 2) * aspectRatio;
2768
+ }
2769
+ var imageX = (size - imageSize) / 2;
2770
+ var imageY = (size - imageSize) / 2 - imageSize / 3;
2771
+ ctx.beginPath();
2772
+ ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, false);
2773
+ var brightness = calculateImageBrightness(img);
2774
+ var bgColor = brightness < 128 ? "white" : "#114d78";
2775
+ var txtColor = brightness < 128 ? "black" : "white";
2776
+ ctx.fillStyle = bgColor;
2777
+ ctx.fill();
2778
+ ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
2779
+ ctx.shadowOffsetX = 3;
2780
+ ctx.shadowOffsetY = 3;
2781
+ ctx.shadowBlur = 5;
2782
+ ctx.drawImage(img, imageX, imageY, imageSize, imageSize);
2783
+ var padding = imageSize / 6;
2784
+ var maxTextWidth = imageSize;
2785
+ var maxTextHeight = imageSize - padding;
2786
+ var minTextSize = Math.floor(imageSize / 5);
2787
+ var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
2788
+ ctx.font = "bold ".concat(textSize, "px Arial");
2789
+ ctx.fillStyle = txtColor;
2790
+ ctx.textAlign = "center";
2791
+ ctx.textBaseline = "top";
2792
+ ctx.shadowColor = "rgba(0, 0, 0, 0)";
2793
+ ctx.shadowOffsetX = 0;
2794
+ ctx.shadowOffsetY = 0;
2795
+ ctx.shadowBlur = 0;
2796
+ ctx.fillText(text, size / 2, imageY + imageSize + padding);
2797
+ };
2798
+ var findOptimalFontSize = function (text, maxWidth, maxHeight, minSize) {
2799
+ var fontSize = maxHeight;
2800
+ var tempCanvas = document.createElement("canvas");
2801
+ var tempCtx = tempCanvas.getContext("2d");
2802
+ while (fontSize > minSize) {
2803
+ tempCtx.font = "bold ".concat(fontSize, "px Arial");
2804
+ var measuredWidth = tempCtx.measureText(text).width;
2805
+ var measuredHeight = fontSize * 1.2; // Allowing some padding
2806
+ if (measuredWidth <= maxWidth && measuredHeight <= maxHeight) {
2807
+ break;
2808
+ }
2809
+ fontSize--;
2810
+ }
2811
+ return fontSize;
2812
+ };
2813
+ var calculateImageBrightness = function (img) {
2814
+ var brightness = 0;
2815
+ var tempCanvas = document.createElement("canvas");
2816
+ tempCanvas.width = img.width;
2817
+ tempCanvas.height = img.height;
2818
+ var tempCtx = tempCanvas.getContext("2d");
2819
+ tempCtx.drawImage(img, 0, 0);
2820
+ var imageData = tempCtx.getImageData(0, 0, img.width, img.height).data;
2821
+ for (var i = 0; i < imageData.length; i += 4) {
2822
+ var r = imageData[i];
2823
+ var g = imageData[i + 1];
2824
+ var b = imageData[i + 2];
2825
+ brightness += (r + g + b) / 3;
2826
+ }
2827
+ return Math.round(brightness / (img.width * img.height));
2828
+ };
2829
+ if (iconUrl) {
2830
+ var img_1 = new Image();
2831
+ img_1.crossOrigin = "anonymous";
2832
+ img_1.src = iconUrl;
2833
+ img_1.onload = function () {
2834
+ if (size > 50) {
2835
+ drawWithImage(img_1);
2836
+ }
2837
+ else {
2838
+ drawWithoutImage(img_1);
2839
+ }
2840
+ res(canvas);
2841
+ };
2842
+ img_1.onerror = function () {
2843
+ drawWithoutImage();
2844
+ res(canvas);
2845
+ };
2846
+ }
2847
+ else {
2848
+ drawWithoutImage();
2849
+ res(canvas);
2850
+ }
2851
+ });
2852
+ _clusterImageCache.Set(key, prom);
2853
+ prom.then(function (canvas) {
2854
+ _clusterImageLoadedCache.Set(key, canvas);
2855
+ _clusterImageCache.Set(key, null);
2856
+ });
2857
+ return [4 /*yield*/, prom];
2858
+ case 3: return [2 /*return*/, _a.sent()];
2859
+ }
2860
+ });
2861
+ });
2862
+ }
2863
+ function getClusterImage(params) {
2864
+ var size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
2865
+ var key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
2866
+ var cacheData = _clusterImageLoadedCache.Get(key);
2867
+ // If available then return.
2868
+ if (cacheData) {
2869
+ return cacheData;
2870
+ }
2871
+ // If not available then queue for it to cook.
2872
+ else {
2873
+ _loadClusterImage(params);
2874
+ }
2875
+ return null;
2876
+ }
2716
2877
  var PointClustering = /** @class */ (function () {
2717
2878
  function PointClustering(register, menuItemId) {
2718
2879
  var _this = this;
@@ -2866,45 +3027,42 @@ var PointClustering = /** @class */ (function () {
2866
3027
  scale = Math.min(scale, 120);
2867
3028
  return scale;
2868
3029
  };
2869
- var getLabel = function (count) {
2870
- var color = _this.pointColorTxt ? _this.pointColorTxt : "white";
2871
- var canvas = document.createElement("canvas");
2872
- var ctx = canvas.getContext("2d");
2873
- var size = getScale(count);
2874
- canvas.width = size;
2875
- canvas.height = size;
2876
- ctx.font = "bold 20px Arial";
2877
- ctx.fillStyle = color;
2878
- ctx.textAlign = "center";
2879
- ctx.textBaseline = "middle";
2880
- ctx.fillText(String(count), size / 2, size / 2);
2881
- return canvas;
3030
+ /**
3031
+ * Generate circle with label in center.
3032
+ * @param count
3033
+ * @returns
3034
+ */
3035
+ var getCanvas = function (count) {
3036
+ var params = {
3037
+ size: getScale(count),
3038
+ txtColor: _this.pointColorTxt,
3039
+ bgColor: _this.pointColorBg,
3040
+ text: String(count),
3041
+ iconUrl: _this.iconUrl
3042
+ };
3043
+ return getClusterImage(params);
2882
3044
  };
2883
- // 5: iterate over clusters and add/update them as Cesium entities.
2884
- for (var _e = 0, clusters_1 = clusters; _e < clusters_1.length; _e++) {
2885
- var cluster = clusters_1[_e];
3045
+ var _loop_1 = function (cluster) {
2886
3046
  var clusterId = cluster.center.id;
2887
- var clusterEntity = this.clusterEntities.get(clusterId);
2888
- var centroid = this.calculateCentroid(cluster.points);
3047
+ var clusterEntity = this_1.clusterEntities.get(clusterId);
3048
+ var centroid = this_1.calculateCentroid(cluster.points);
2889
3049
  var count = cluster.points.length;
2890
3050
  if (clusterEntity) {
2891
3051
  clusterEntity.position = Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150);
2892
- clusterEntity.point.pixelSize = getScale(cluster.points.length);
2893
- clusterEntity.billboard.image = getLabel(cluster.points.length);
2894
- clusterEntity.billboard.width = getScale(cluster.points.length);
3052
+ clusterEntity.billboard.image = new CallbackProperty(function () {
3053
+ return getCanvas(count);
3054
+ }, false),
3055
+ clusterEntity.billboard.width = getScale(cluster.points.length);
2895
3056
  clusterEntity.billboard.height = getScale(cluster.points.length);
2896
3057
  }
2897
3058
  else {
2898
- clusterEntity = this.viewer.entities.add({
3059
+ clusterEntity = this_1.viewer.entities.add({
2899
3060
  position: Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150),
2900
- point: {
2901
- heightReference: HeightReference.NONE,
2902
- pixelSize: getScale(count),
2903
- color: this.pointColorBg ? this.pointColorBg : Color.fromCssColorString("#4287f5")
2904
- },
2905
3061
  billboard: {
2906
3062
  heightReference: HeightReference.NONE,
2907
- image: getLabel(count),
3063
+ image: new CallbackProperty(function () {
3064
+ return getCanvas(count);
3065
+ }, false),
2908
3066
  width: getScale(count),
2909
3067
  height: getScale(count),
2910
3068
  verticalOrigin: VerticalOrigin.CENTER,
@@ -2912,33 +3070,39 @@ var PointClustering = /** @class */ (function () {
2912
3070
  disableDepthTestDistance: Number.POSITIVE_INFINITY
2913
3071
  }
2914
3072
  });
2915
- this.clusterEntities.set(clusterId, clusterEntity);
3073
+ this_1.clusterEntities.set(clusterId, clusterEntity);
2916
3074
  }
2917
3075
  for (var i = 0; i < cluster.points.length; i++) {
2918
3076
  var entityId = cluster.points[i].id;
2919
- var rego = this.register.GetRego({
3077
+ var rego = this_1.register.GetRego({
2920
3078
  entityId: entityId,
2921
- menuItemId: this.menuItemId
3079
+ menuItemId: this_1.menuItemId
2922
3080
  });
2923
3081
  if (rego && !rego.suppressShow) {
2924
3082
  rego.suppressShow = true;
2925
- this.register.ForceUpdate({
3083
+ this_1.register.ForceUpdate({
2926
3084
  entityIds: [entityId],
2927
3085
  });
2928
3086
  }
2929
3087
  }
3088
+ };
3089
+ var this_1 = this;
3090
+ // 5: iterate over clusters and add/update them as Cesium entities.
3091
+ for (var _e = 0, clusters_1 = clusters; _e < clusters_1.length; _e++) {
3092
+ var cluster = clusters_1[_e];
3093
+ _loop_1(cluster);
2930
3094
  }
2931
- var _loop_1 = function (clusterId, clusterEntity) {
3095
+ var _loop_2 = function (clusterId, clusterEntity) {
2932
3096
  if (!clusters.find(function (x) { return x.center.id == clusterId; })) {
2933
- this_1.viewer.entities.remove(clusterEntity);
2934
- this_1.clusterEntities.delete(clusterId);
3097
+ this_2.viewer.entities.remove(clusterEntity);
3098
+ this_2.clusterEntities.delete(clusterId);
2935
3099
  }
2936
3100
  };
2937
- var this_1 = this;
3101
+ var this_2 = this;
2938
3102
  // 6: Iterate over existing cluster entities and remove those that are no longer clustered.
2939
3103
  for (var _f = 0, _g = Array.from(this.clusterEntities); _f < _g.length; _f++) {
2940
3104
  var _h = _g[_f], clusterId = _h[0], clusterEntity = _h[1];
2941
- _loop_1(clusterId, clusterEntity);
3105
+ _loop_2(clusterId, clusterEntity);
2942
3106
  }
2943
3107
  };
2944
3108
  /**
@@ -2947,7 +3111,7 @@ var PointClustering = /** @class */ (function () {
2947
3111
  */
2948
3112
  PointClustering.prototype.updateClusterSpacing = function (cameraHeight) {
2949
3113
  // Camera height thresholds in meters.
2950
- var cameraHeightThresholds = [2000, 5000, 8000, 13000, 25000, 40000];
3114
+ var cameraHeightThresholds = [4000, 5000, 8000, 13000, 25000, 40000];
2951
3115
  // Distance increments in degrees.
2952
3116
  var distanceIncrements = [0.005, 0.01, 0.02, 0.04, 0.1, 0.5];
2953
3117
  // Find the appropriate spacing based on the camera height.
@@ -2977,9 +3141,9 @@ var PointClustering = /** @class */ (function () {
2977
3141
  if (processedPoints.has(point.id)) {
2978
3142
  continue;
2979
3143
  }
2980
- // Skip points closer than 2000 meters to the camera.
3144
+ // Skip points closer than 4000 meters to the camera.
2981
3145
  var cartesian3 = Cartesian3.fromDegrees(point.lon, point.lat);
2982
- if (Cartesian3.distance(cartesian3, cameraPosition) <= 2000) {
3146
+ if (Cartesian3.distance(cartesian3, cameraPosition) <= 4000) {
2983
3147
  continue;
2984
3148
  }
2985
3149
  var found = [];
@@ -3108,14 +3272,14 @@ var PointClustering = /** @class */ (function () {
3108
3272
  return false;
3109
3273
  }
3110
3274
  if (!this.pointColorBg && entity.point) {
3111
- this.pointColorBg = GetValue$1(this.viewer, entity.point.color);
3112
- if (this.pointColorBg) {
3275
+ var pointColorBg = GetValue$1(this.viewer, entity.point.color);
3276
+ if (pointColorBg) {
3113
3277
  var cColor = null;
3114
- if (this.pointColorBg instanceof Object) {
3115
- cColor = new Color(this.pointColorBg.red, this.pointColorBg.green, this.pointColorBg.blue, this.pointColorBg.alpha);
3278
+ if (pointColorBg instanceof Object) {
3279
+ cColor = new Color(pointColorBg.red, pointColorBg.green, pointColorBg.blue, pointColorBg.alpha);
3116
3280
  }
3117
- else if (typeof this.pointColorBg === "string") {
3118
- cColor = Color.fromCssColorString(this.pointColorBg);
3281
+ else if (typeof pointColorBg === "string") {
3282
+ cColor = Color.fromCssColorString(pointColorBg);
3119
3283
  }
3120
3284
  // Determine if text color should instead be black based on background.
3121
3285
  // cColor contains r,g,b,a values where r,g,b are in the range [0,1].
@@ -3127,9 +3291,16 @@ var PointClustering = /** @class */ (function () {
3127
3291
  else {
3128
3292
  this.pointColorTxt = "white";
3129
3293
  }
3294
+ this.pointColorBg = cColor.toCssColorString();
3130
3295
  }
3131
3296
  }
3132
3297
  }
3298
+ if (!this.iconUrl && entity.billboard) {
3299
+ var iconUrl = GetValue$1(this.viewer, entity.billboard.image);
3300
+ if (typeof iconUrl == "string") {
3301
+ this.iconUrl = iconUrl;
3302
+ }
3303
+ }
3133
3304
  this.registeredEntityIds.add(id);
3134
3305
  this.addPoint(id, pos3d);
3135
3306
  this.updateQueue.Call();
@@ -10662,7 +10833,7 @@ var ViewRenderEngine;
10662
10833
  ViewRenderEngine.Render = Render;
10663
10834
  })(ViewRenderEngine || (ViewRenderEngine = {}));
10664
10835
 
10665
- var VERSION = "2.1.8";
10836
+ var VERSION = "2.1.9";
10666
10837
 
10667
10838
  export { VERSION, CesiumViewMonitor, ViewerUtils, MenuItemManager, EntityRenderEngine, MenuItemCreator, VisualsRegister, RenderManager, EntitiesIdsRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, TilesetCadRenderManager, TilesetArbRenderManager, TilesetEntitiesRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TilesetGooglePhotosRenderManager, DataSourceStaticKmlManager, RelationsRenderManager, SharedGetters, CesiumParabola, ViewRenderEngine, TileRenderEngine, TilesetRenderEngine, CESIUM_INSPECTOR_KEY, ViewUtils, DrawingUtils, MeasureUtils, EntityUtils };
10668
10839
  //# sourceMappingURL=bruce-cesium.es5.js.map