bruce-cesium 2.1.8 → 2.2.0
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 +365 -161
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +364 -160
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/render-managers/common/point-clustering.js +398 -158
- package/dist/lib/rendering/render-managers/common/point-clustering.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/render-managers/common/point-clustering.d.ts +6 -25
- package/package.json +1 -1
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -2708,19 +2708,208 @@
|
|
|
2708
2708
|
this.southeast.Remove(point);
|
|
2709
2709
|
}
|
|
2710
2710
|
};
|
|
2711
|
+
Quad.prototype.GetDistanceToQuad = function (pos3d) {
|
|
2712
|
+
var minLat = this.boundary.y - this.boundary.h;
|
|
2713
|
+
var maxLat = this.boundary.y + this.boundary.h;
|
|
2714
|
+
var minLon = this.boundary.x - this.boundary.w;
|
|
2715
|
+
var maxLon = this.boundary.x + this.boundary.w;
|
|
2716
|
+
var points = [
|
|
2717
|
+
// Corners.
|
|
2718
|
+
new Cesium.Cartesian3(minLon, minLat, 0),
|
|
2719
|
+
new Cesium.Cartesian3(minLon, maxLat, 0),
|
|
2720
|
+
new Cesium.Cartesian3(maxLon, minLat, 0),
|
|
2721
|
+
new Cesium.Cartesian3(maxLon, maxLat, 0),
|
|
2722
|
+
// Center.
|
|
2723
|
+
new Cesium.Cartesian3(this.boundary.x, this.boundary.y, 0)
|
|
2724
|
+
];
|
|
2725
|
+
var shortest = Number.MAX_VALUE;
|
|
2726
|
+
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
|
|
2727
|
+
var point = points_1[_i];
|
|
2728
|
+
var distance = Cesium.Cartesian3.distance(pos3d, point);
|
|
2729
|
+
if (distance < shortest) {
|
|
2730
|
+
shortest = distance;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
return shortest;
|
|
2734
|
+
};
|
|
2711
2735
|
return Quad;
|
|
2712
2736
|
}());
|
|
2737
|
+
var _clusterImageCache = new bruceModels.LRUCache(500);
|
|
2738
|
+
var _clusterImageLoadedCache = new bruceModels.LRUCache(500);
|
|
2739
|
+
function _loadClusterImage(params) {
|
|
2740
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2741
|
+
var size, txtColor, bgColor, text, iconUrl, key, cacheData, prom;
|
|
2742
|
+
return __generator(this, function (_a) {
|
|
2743
|
+
switch (_a.label) {
|
|
2744
|
+
case 0:
|
|
2745
|
+
size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
|
|
2746
|
+
key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
|
|
2747
|
+
cacheData = _clusterImageCache.Get(key);
|
|
2748
|
+
if (!cacheData) return [3 /*break*/, 2];
|
|
2749
|
+
return [4 /*yield*/, cacheData];
|
|
2750
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
2751
|
+
case 2:
|
|
2752
|
+
prom = new Promise(function (res, rej) {
|
|
2753
|
+
var canvas = document.createElement("canvas");
|
|
2754
|
+
canvas.width = size;
|
|
2755
|
+
canvas.height = size;
|
|
2756
|
+
var ctx = canvas.getContext("2d");
|
|
2757
|
+
var WHITESPACE_PADDING_PERCENT = 0.05;
|
|
2758
|
+
var radius = (size / 2) - (size * WHITESPACE_PADDING_PERCENT);
|
|
2759
|
+
var drawWithoutImage = function (img) {
|
|
2760
|
+
ctx.beginPath();
|
|
2761
|
+
ctx.arc(size / 2, size / 2, radius, 0, 2 * Math.PI, false);
|
|
2762
|
+
var fill = null;
|
|
2763
|
+
var txt = null;
|
|
2764
|
+
if (img) {
|
|
2765
|
+
var brightness = calculateImageBrightness(img);
|
|
2766
|
+
fill = brightness < 128 ? "white" : "#114d78";
|
|
2767
|
+
txt = brightness < 128 ? "black" : "white";
|
|
2768
|
+
}
|
|
2769
|
+
else {
|
|
2770
|
+
fill = bgColor ? bgColor : "#114d78";
|
|
2771
|
+
txt = txtColor ? txtColor : "white";
|
|
2772
|
+
}
|
|
2773
|
+
ctx.fillStyle = fill;
|
|
2774
|
+
ctx.fill();
|
|
2775
|
+
var maxTextWidth = size * 0.7;
|
|
2776
|
+
var maxTextHeight = size * 0.7;
|
|
2777
|
+
var minTextSize = Math.floor(size / 12);
|
|
2778
|
+
var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
|
|
2779
|
+
ctx.font = "bold ".concat(textSize, "px Arial");
|
|
2780
|
+
ctx.fillStyle = txt;
|
|
2781
|
+
ctx.textAlign = "center";
|
|
2782
|
+
ctx.textBaseline = "middle";
|
|
2783
|
+
ctx.fillText(text, size / 2, size / 2);
|
|
2784
|
+
};
|
|
2785
|
+
var drawWithImage = function (img) {
|
|
2786
|
+
var aspectRatio = img.width / img.height;
|
|
2787
|
+
var imageSize = Math.min(radius, img.width, img.height);
|
|
2788
|
+
if (imageSize / aspectRatio > radius) {
|
|
2789
|
+
imageSize = radius * aspectRatio;
|
|
2790
|
+
}
|
|
2791
|
+
var imageX = (size - imageSize) / 2;
|
|
2792
|
+
var imageY = (size - imageSize) / 2 - imageSize / 3;
|
|
2793
|
+
ctx.beginPath();
|
|
2794
|
+
ctx.arc(size / 2, size / 2, radius, 0, 2 * Math.PI, false);
|
|
2795
|
+
var brightness = calculateImageBrightness(img);
|
|
2796
|
+
var bgColor = brightness < 128 ? "white" : "#114d78";
|
|
2797
|
+
var txtColor = brightness < 128 ? "black" : "white";
|
|
2798
|
+
ctx.fillStyle = bgColor;
|
|
2799
|
+
ctx.fill();
|
|
2800
|
+
ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
|
|
2801
|
+
ctx.shadowOffsetX = 3;
|
|
2802
|
+
ctx.shadowOffsetY = 3;
|
|
2803
|
+
ctx.shadowBlur = 5;
|
|
2804
|
+
ctx.drawImage(img, imageX, imageY, imageSize, imageSize);
|
|
2805
|
+
var padding = imageSize / 7;
|
|
2806
|
+
var maxTextWidth = imageSize;
|
|
2807
|
+
var maxTextHeight = imageSize - padding;
|
|
2808
|
+
var minTextSize = Math.floor(imageSize / 5);
|
|
2809
|
+
var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
|
|
2810
|
+
ctx.font = "bold ".concat(textSize, "px Arial");
|
|
2811
|
+
ctx.fillStyle = txtColor;
|
|
2812
|
+
ctx.textAlign = "center";
|
|
2813
|
+
ctx.textBaseline = "top";
|
|
2814
|
+
ctx.shadowColor = "rgba(0, 0, 0, 0)";
|
|
2815
|
+
ctx.shadowOffsetX = 0;
|
|
2816
|
+
ctx.shadowOffsetY = 0;
|
|
2817
|
+
ctx.shadowBlur = 0;
|
|
2818
|
+
ctx.fillText(text, size / 2, imageY + imageSize + padding);
|
|
2819
|
+
};
|
|
2820
|
+
var findOptimalFontSize = function (text, maxWidth, maxHeight, minSize) {
|
|
2821
|
+
var fontSize = maxHeight;
|
|
2822
|
+
var tempCanvas = document.createElement("canvas");
|
|
2823
|
+
var tempCtx = tempCanvas.getContext("2d");
|
|
2824
|
+
while (fontSize > minSize) {
|
|
2825
|
+
tempCtx.font = "bold ".concat(fontSize, "px Arial");
|
|
2826
|
+
var measuredWidth = tempCtx.measureText(text).width;
|
|
2827
|
+
var measuredHeight = fontSize * 1.2;
|
|
2828
|
+
if (measuredWidth <= maxWidth && measuredHeight <= maxHeight) {
|
|
2829
|
+
break;
|
|
2830
|
+
}
|
|
2831
|
+
fontSize--;
|
|
2832
|
+
}
|
|
2833
|
+
return fontSize;
|
|
2834
|
+
};
|
|
2835
|
+
var calculateImageBrightness = function (img) {
|
|
2836
|
+
var brightness = 0;
|
|
2837
|
+
var tempCanvas = document.createElement("canvas");
|
|
2838
|
+
tempCanvas.width = img.width;
|
|
2839
|
+
tempCanvas.height = img.height;
|
|
2840
|
+
var tempCtx = tempCanvas.getContext("2d");
|
|
2841
|
+
tempCtx.drawImage(img, 0, 0);
|
|
2842
|
+
var imageData = tempCtx.getImageData(0, 0, img.width, img.height).data;
|
|
2843
|
+
for (var i = 0; i < imageData.length; i += 4) {
|
|
2844
|
+
var r = imageData[i];
|
|
2845
|
+
var g = imageData[i + 1];
|
|
2846
|
+
var b = imageData[i + 2];
|
|
2847
|
+
brightness += (r + g + b) / 3;
|
|
2848
|
+
}
|
|
2849
|
+
return Math.round(brightness / (img.width * img.height));
|
|
2850
|
+
};
|
|
2851
|
+
if (iconUrl) {
|
|
2852
|
+
var img_1 = new Image();
|
|
2853
|
+
img_1.crossOrigin = "anonymous";
|
|
2854
|
+
img_1.src = iconUrl;
|
|
2855
|
+
img_1.onload = function () {
|
|
2856
|
+
if (size > 50) {
|
|
2857
|
+
drawWithImage(img_1);
|
|
2858
|
+
}
|
|
2859
|
+
else {
|
|
2860
|
+
drawWithoutImage(img_1);
|
|
2861
|
+
}
|
|
2862
|
+
res(canvas);
|
|
2863
|
+
};
|
|
2864
|
+
img_1.onerror = function () {
|
|
2865
|
+
drawWithoutImage();
|
|
2866
|
+
res(canvas);
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
else {
|
|
2870
|
+
drawWithoutImage();
|
|
2871
|
+
res(canvas);
|
|
2872
|
+
}
|
|
2873
|
+
});
|
|
2874
|
+
_clusterImageCache.Set(key, prom);
|
|
2875
|
+
prom.then(function (canvas) {
|
|
2876
|
+
_clusterImageLoadedCache.Set(key, canvas);
|
|
2877
|
+
_clusterImageCache.Set(key, null);
|
|
2878
|
+
});
|
|
2879
|
+
return [4 /*yield*/, prom];
|
|
2880
|
+
case 3: return [2 /*return*/, _a.sent()];
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
function getClusterImage(params) {
|
|
2886
|
+
var size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
|
|
2887
|
+
var key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
|
|
2888
|
+
var cacheData = _clusterImageLoadedCache.Get(key);
|
|
2889
|
+
// If available then return.
|
|
2890
|
+
if (cacheData) {
|
|
2891
|
+
return cacheData;
|
|
2892
|
+
}
|
|
2893
|
+
// If not available then queue for it to cook.
|
|
2894
|
+
else {
|
|
2895
|
+
_loadClusterImage(params);
|
|
2896
|
+
}
|
|
2897
|
+
return null;
|
|
2898
|
+
}
|
|
2899
|
+
var FORCE_UPDATE_BATCH_SIZE = 1000;
|
|
2900
|
+
var FORCE_UPDATE_BATCH_DELAY = 100;
|
|
2713
2901
|
var PointClustering = /** @class */ (function () {
|
|
2714
2902
|
function PointClustering(register, menuItemId) {
|
|
2715
2903
|
var _this = this;
|
|
2716
2904
|
this.disposed = false;
|
|
2717
2905
|
this.registeredEntityIds = new Set();
|
|
2906
|
+
// Queue to force update entities.
|
|
2907
|
+
this.updateEntityQueue = [];
|
|
2718
2908
|
this.register = register;
|
|
2719
2909
|
this.viewer = register.Viewer;
|
|
2720
2910
|
this.menuItemId = menuItemId;
|
|
2721
|
-
this.updateClusterSpacing(0);
|
|
2722
2911
|
var boundary = new Rectangle(0, 0, 360, 180);
|
|
2723
|
-
this.quadTree = new Quad(boundary,
|
|
2912
|
+
this.quadTree = new Quad(boundary, 30);
|
|
2724
2913
|
this.prevClusteredEntities = new Set();
|
|
2725
2914
|
this.currClusteredEntities = new Set();
|
|
2726
2915
|
this.clusterEntities = new Map();
|
|
@@ -2729,6 +2918,39 @@
|
|
|
2729
2918
|
}, 1000);
|
|
2730
2919
|
this.listenCamera();
|
|
2731
2920
|
}
|
|
2921
|
+
PointClustering.prototype.queueForceUpdate = function (entityIds) {
|
|
2922
|
+
for (var i = 0; i < entityIds.length; i++) {
|
|
2923
|
+
if (this.updateEntityQueue.includes(entityIds[i])) {
|
|
2924
|
+
continue;
|
|
2925
|
+
}
|
|
2926
|
+
this.updateEntityQueue.push(entityIds[i]);
|
|
2927
|
+
}
|
|
2928
|
+
this.runForceUpdateQueue();
|
|
2929
|
+
};
|
|
2930
|
+
PointClustering.prototype.runForceUpdateQueue = function () {
|
|
2931
|
+
var _this = this;
|
|
2932
|
+
if (!this.updateEntityQueue.length) {
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2935
|
+
if (this.queueInterval) {
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
this.queueInterval = setInterval(function () {
|
|
2939
|
+
if (_this.disposed) {
|
|
2940
|
+
clearInterval(_this.queueInterval);
|
|
2941
|
+
_this.queueInterval = null;
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
var ids = _this.updateEntityQueue.splice(0, FORCE_UPDATE_BATCH_SIZE);
|
|
2945
|
+
_this.register.ForceUpdate({
|
|
2946
|
+
entityIds: ids
|
|
2947
|
+
});
|
|
2948
|
+
if (!_this.updateEntityQueue.length) {
|
|
2949
|
+
clearInterval(_this.queueInterval);
|
|
2950
|
+
_this.queueInterval = null;
|
|
2951
|
+
}
|
|
2952
|
+
}, FORCE_UPDATE_BATCH_DELAY);
|
|
2953
|
+
};
|
|
2732
2954
|
/**
|
|
2733
2955
|
* Starts listening to camera changes.
|
|
2734
2956
|
* This will trigger the clustering update whenever camera is moved.
|
|
@@ -2783,6 +3005,7 @@
|
|
|
2783
3005
|
this.clusterEntities.clear();
|
|
2784
3006
|
this.unlistenCamera();
|
|
2785
3007
|
this.disposed = true;
|
|
3008
|
+
this.updateEntityQueue = [];
|
|
2786
3009
|
// Restore entities.
|
|
2787
3010
|
var toUpdateIds = [];
|
|
2788
3011
|
for (var _c = 0, _d = Array.from(this.registeredEntityIds); _c < _d.length; _c++) {
|
|
@@ -2810,8 +3033,8 @@
|
|
|
2810
3033
|
PointClustering.prototype.calculateCentroid = function (points) {
|
|
2811
3034
|
var lonSum = 0;
|
|
2812
3035
|
var latSum = 0;
|
|
2813
|
-
for (var _i = 0,
|
|
2814
|
-
var point =
|
|
3036
|
+
for (var _i = 0, points_2 = points; _i < points_2.length; _i++) {
|
|
3037
|
+
var point = points_2[_i];
|
|
2815
3038
|
lonSum += point.lon;
|
|
2816
3039
|
latSum += point.lat;
|
|
2817
3040
|
}
|
|
@@ -2831,9 +3054,10 @@
|
|
|
2831
3054
|
// 1: Update precision.
|
|
2832
3055
|
// This defines how far apart these clusters can be.
|
|
2833
3056
|
var cameraHeight = this.viewer.camera.positionCartographic.height;
|
|
2834
|
-
this.
|
|
3057
|
+
this.getClusterSpacing(cameraHeight);
|
|
2835
3058
|
// 2: Get clusters.
|
|
2836
3059
|
var _a = this.getClusters(), clusters = _a.clusters, noLongerClustered = _a.noLongerClustered;
|
|
3060
|
+
var entitiesToUpdate = [];
|
|
2837
3061
|
// 3: Remove all cesium cluster entities that are no longer clustered.
|
|
2838
3062
|
for (var _i = 0, _b = Array.from(noLongerClustered); _i < _b.length; _i++) {
|
|
2839
3063
|
var id = _b[_i];
|
|
@@ -2850,193 +3074,180 @@
|
|
|
2850
3074
|
});
|
|
2851
3075
|
if (rego && rego.suppressShow) {
|
|
2852
3076
|
rego.suppressShow = false;
|
|
2853
|
-
|
|
2854
|
-
entityIds: [id],
|
|
2855
|
-
});
|
|
3077
|
+
entitiesToUpdate.push(id);
|
|
2856
3078
|
}
|
|
2857
3079
|
}
|
|
2858
3080
|
}
|
|
2859
3081
|
var getScale = function (count) {
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
scale =
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
return
|
|
3082
|
+
// const MIN_SCALE = 15;
|
|
3083
|
+
// const MAX_SCALE = 80;
|
|
3084
|
+
// const SCALE_PER_POINT = 1.01;
|
|
3085
|
+
// let scale = MIN_SCALE + (count * SCALE_PER_POINT);
|
|
3086
|
+
// scale = Math.min(scale, MAX_SCALE);
|
|
3087
|
+
// return scale;
|
|
3088
|
+
if (count >= 10000) {
|
|
3089
|
+
return 140;
|
|
3090
|
+
}
|
|
3091
|
+
if (count >= 1000) {
|
|
3092
|
+
return 120;
|
|
3093
|
+
}
|
|
3094
|
+
if (count >= 100) {
|
|
3095
|
+
return 90;
|
|
3096
|
+
}
|
|
3097
|
+
if (count >= 10) {
|
|
3098
|
+
return 80;
|
|
3099
|
+
}
|
|
3100
|
+
return 70;
|
|
2879
3101
|
};
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3102
|
+
/**
|
|
3103
|
+
* Generate circle with label in center.
|
|
3104
|
+
* @param count
|
|
3105
|
+
* @returns
|
|
3106
|
+
*/
|
|
3107
|
+
var getCanvas = function (count) {
|
|
3108
|
+
var params = {
|
|
3109
|
+
size: getScale(count),
|
|
3110
|
+
txtColor: _this.pointColorTxt,
|
|
3111
|
+
bgColor: _this.pointColorBg,
|
|
3112
|
+
text: String(count),
|
|
3113
|
+
iconUrl: _this.iconUrl
|
|
3114
|
+
};
|
|
3115
|
+
return getClusterImage(params);
|
|
3116
|
+
};
|
|
3117
|
+
var _loop_1 = function (cluster) {
|
|
2883
3118
|
var clusterId = cluster.center.id;
|
|
2884
|
-
var clusterEntity =
|
|
2885
|
-
var centroid =
|
|
3119
|
+
var clusterEntity = this_1.clusterEntities.get(clusterId);
|
|
3120
|
+
var centroid = this_1.calculateCentroid(cluster.points);
|
|
2886
3121
|
var count = cluster.points.length;
|
|
2887
3122
|
if (clusterEntity) {
|
|
2888
3123
|
clusterEntity.position = Cesium.Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150);
|
|
2889
|
-
clusterEntity.
|
|
2890
|
-
|
|
2891
|
-
|
|
3124
|
+
clusterEntity.billboard.image = new Cesium.CallbackProperty(function () {
|
|
3125
|
+
return getCanvas(count);
|
|
3126
|
+
}, false),
|
|
3127
|
+
clusterEntity.billboard.width = getScale(cluster.points.length);
|
|
2892
3128
|
clusterEntity.billboard.height = getScale(cluster.points.length);
|
|
2893
3129
|
}
|
|
2894
3130
|
else {
|
|
2895
|
-
clusterEntity =
|
|
3131
|
+
clusterEntity = this_1.viewer.entities.add({
|
|
2896
3132
|
position: Cesium.Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150),
|
|
2897
|
-
point: {
|
|
2898
|
-
heightReference: Cesium.HeightReference.NONE,
|
|
2899
|
-
pixelSize: getScale(count),
|
|
2900
|
-
color: this.pointColorBg ? this.pointColorBg : Cesium.Color.fromCssColorString("#4287f5")
|
|
2901
|
-
},
|
|
2902
3133
|
billboard: {
|
|
2903
3134
|
heightReference: Cesium.HeightReference.NONE,
|
|
2904
|
-
image:
|
|
3135
|
+
image: new Cesium.CallbackProperty(function () {
|
|
3136
|
+
return getCanvas(count);
|
|
3137
|
+
}, false),
|
|
2905
3138
|
width: getScale(count),
|
|
2906
3139
|
height: getScale(count),
|
|
2907
3140
|
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
|
2908
3141
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
|
2909
|
-
disableDepthTestDistance: Number.POSITIVE_INFINITY
|
|
3142
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
3143
|
+
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 0.5, 3.0e7, 0.1),
|
|
2910
3144
|
}
|
|
2911
3145
|
});
|
|
2912
|
-
|
|
3146
|
+
this_1.clusterEntities.set(clusterId, clusterEntity);
|
|
2913
3147
|
}
|
|
2914
3148
|
for (var i = 0; i < cluster.points.length; i++) {
|
|
2915
3149
|
var entityId = cluster.points[i].id;
|
|
2916
|
-
var rego =
|
|
3150
|
+
var rego = this_1.register.GetRego({
|
|
2917
3151
|
entityId: entityId,
|
|
2918
|
-
menuItemId:
|
|
3152
|
+
menuItemId: this_1.menuItemId
|
|
2919
3153
|
});
|
|
2920
3154
|
if (rego && !rego.suppressShow) {
|
|
2921
3155
|
rego.suppressShow = true;
|
|
2922
|
-
|
|
2923
|
-
entityIds: [entityId],
|
|
2924
|
-
});
|
|
3156
|
+
entitiesToUpdate.push(entityId);
|
|
2925
3157
|
}
|
|
2926
3158
|
}
|
|
3159
|
+
};
|
|
3160
|
+
var this_1 = this;
|
|
3161
|
+
// 5: iterate over clusters and add/update them as Cesium entities.
|
|
3162
|
+
for (var _e = 0, clusters_1 = clusters; _e < clusters_1.length; _e++) {
|
|
3163
|
+
var cluster = clusters_1[_e];
|
|
3164
|
+
_loop_1(cluster);
|
|
2927
3165
|
}
|
|
2928
|
-
|
|
3166
|
+
this.queueForceUpdate(entitiesToUpdate);
|
|
3167
|
+
var _loop_2 = function (clusterId, clusterEntity) {
|
|
2929
3168
|
if (!clusters.find(function (x) { return x.center.id == clusterId; })) {
|
|
2930
|
-
|
|
2931
|
-
|
|
3169
|
+
this_2.viewer.entities.remove(clusterEntity);
|
|
3170
|
+
this_2.clusterEntities.delete(clusterId);
|
|
2932
3171
|
}
|
|
2933
3172
|
};
|
|
2934
|
-
var
|
|
3173
|
+
var this_2 = this;
|
|
2935
3174
|
// 6: Iterate over existing cluster entities and remove those that are no longer clustered.
|
|
2936
3175
|
for (var _f = 0, _g = Array.from(this.clusterEntities); _f < _g.length; _f++) {
|
|
2937
3176
|
var _h = _g[_f], clusterId = _h[0], clusterEntity = _h[1];
|
|
2938
|
-
|
|
3177
|
+
_loop_2(clusterId, clusterEntity);
|
|
2939
3178
|
}
|
|
2940
3179
|
};
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
*/
|
|
2945
|
-
PointClustering.prototype.updateClusterSpacing = function (cameraHeight) {
|
|
2946
|
-
// Camera height thresholds in meters.
|
|
2947
|
-
var cameraHeightThresholds = [2000, 5000, 8000, 13000, 25000, 40000];
|
|
3180
|
+
PointClustering.prototype.getClusterSpacing = function (distanceFromCluster) {
|
|
3181
|
+
// Distance thresholds in meters from the cluster.
|
|
3182
|
+
var distanceThresholds = [3000, 4000, 5300, 6000, 7000];
|
|
2948
3183
|
// Distance increments in degrees.
|
|
2949
|
-
var distanceIncrements = [0.
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
3184
|
+
var distanceIncrements = [0.001, 0.002, 0.01, 0.03, 0.09];
|
|
3185
|
+
var index = 0;
|
|
3186
|
+
if (distanceFromCluster) {
|
|
3187
|
+
for (var i = 0; i < distanceThresholds.length; i++) {
|
|
3188
|
+
if (distanceFromCluster > distanceThresholds[i]) {
|
|
3189
|
+
index = i;
|
|
3190
|
+
}
|
|
2956
3191
|
}
|
|
2957
|
-
spacing += distanceIncrements[i];
|
|
2958
3192
|
}
|
|
2959
|
-
|
|
3193
|
+
return distanceIncrements[index];
|
|
2960
3194
|
};
|
|
2961
|
-
/**
|
|
2962
|
-
* Gathers clusters.
|
|
2963
|
-
* @returns
|
|
2964
|
-
*/
|
|
2965
3195
|
PointClustering.prototype.getClusters = function () {
|
|
2966
3196
|
var _this = this;
|
|
2967
3197
|
this.currClusteredEntities.clear();
|
|
2968
3198
|
var clusters = [];
|
|
2969
3199
|
var processedPoints = new Set();
|
|
2970
3200
|
var cameraPosition = this.viewer.camera.position;
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
//
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3201
|
+
var MIN_CAMERA_DISTANCE = 5000;
|
|
3202
|
+
var processQuad = function (quad) {
|
|
3203
|
+
// Distance to quad.
|
|
3204
|
+
// TODO: Needs improvement.
|
|
3205
|
+
var distanceToQuad = quad.GetDistanceToQuad(cameraPosition);
|
|
3206
|
+
// Skip quads that are too close.
|
|
3207
|
+
if (distanceToQuad >= MIN_CAMERA_DISTANCE) {
|
|
3208
|
+
for (var _i = 0, _a = quad.points; _i < _a.length; _i++) {
|
|
3209
|
+
var point = _a[_i];
|
|
3210
|
+
// Skip points already processed in previous clusters.
|
|
3211
|
+
if (processedPoints.has(point.id)) {
|
|
3212
|
+
continue;
|
|
3213
|
+
}
|
|
3214
|
+
// Skip points closer than MIN_CAMERA_DISTANCE meters to the camera.
|
|
3215
|
+
var cartesian3 = Cesium.Cartesian3.fromDegrees(point.lon, point.lat);
|
|
3216
|
+
var distanceFromCluster = Cesium.Cartesian3.distance(cartesian3, cameraPosition);
|
|
3217
|
+
if (distanceFromCluster <= MIN_CAMERA_DISTANCE) {
|
|
3218
|
+
continue;
|
|
3219
|
+
}
|
|
3220
|
+
var found = [];
|
|
3221
|
+
var nearbyPoints = quad.Query(new Circle(point.lon, point.lat, _this.getClusterSpacing(distanceFromCluster)), found);
|
|
3222
|
+
if (nearbyPoints.length > 1) {
|
|
3223
|
+
var cluster = { center: point, points: [] };
|
|
3224
|
+
for (var _b = 0, nearbyPoints_1 = nearbyPoints; _b < nearbyPoints_1.length; _b++) {
|
|
3225
|
+
var nearby = nearbyPoints_1[_b];
|
|
3226
|
+
if (!cluster.points.includes(nearby)) {
|
|
3227
|
+
cluster.points.push(nearby);
|
|
3228
|
+
processedPoints.add(nearby.id);
|
|
3229
|
+
_this.currClusteredEntities.add(nearby.id);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
clusters.push(cluster);
|
|
2992
3233
|
}
|
|
2993
3234
|
}
|
|
2994
|
-
clusters.push(cluster);
|
|
2995
3235
|
}
|
|
2996
|
-
|
|
3236
|
+
if (quad.divided) {
|
|
3237
|
+
processQuad(quad.northwest);
|
|
3238
|
+
processQuad(quad.northeast);
|
|
3239
|
+
processQuad(quad.southwest);
|
|
3240
|
+
processQuad(quad.southeast);
|
|
3241
|
+
}
|
|
3242
|
+
};
|
|
3243
|
+
processQuad(this.quadTree);
|
|
2997
3244
|
// Filter out clusters with only one point.
|
|
2998
3245
|
var validClusters = clusters.filter(function (cluster) { return cluster.points.length > 1; });
|
|
2999
|
-
// Merge adjacent clusters.
|
|
3000
|
-
var mergedClusters = this.mergeClusters(validClusters);
|
|
3001
3246
|
// Get the entity IDs that are no longer clustered
|
|
3002
3247
|
var noLongerClustered = new Set(Array.from(this.prevClusteredEntities).filter(function (id) { return !_this.currClusteredEntities.has(id); }));
|
|
3003
3248
|
// Update the previous clustered entities ref.
|
|
3004
3249
|
this.prevClusteredEntities = new Set(this.currClusteredEntities);
|
|
3005
|
-
return { clusters:
|
|
3006
|
-
};
|
|
3007
|
-
/**
|
|
3008
|
-
* Merges clusters that are nearby based on the distanceBetweenClusters value.
|
|
3009
|
-
* @param clusters
|
|
3010
|
-
* @returns
|
|
3011
|
-
*/
|
|
3012
|
-
PointClustering.prototype.mergeClusters = function (clusters) {
|
|
3013
|
-
var _a;
|
|
3014
|
-
var mergedClusters = [].concat(clusters);
|
|
3015
|
-
// Keep looping while merges keep happening.
|
|
3016
|
-
var mergeOccurred = true;
|
|
3017
|
-
while (mergeOccurred) {
|
|
3018
|
-
mergeOccurred = false;
|
|
3019
|
-
for (var i = 0; i < mergedClusters.length - 1; i++) {
|
|
3020
|
-
for (var j = i + 1; j < mergedClusters.length; j++) {
|
|
3021
|
-
var cluster1 = mergedClusters[i];
|
|
3022
|
-
var cluster2 = mergedClusters[j];
|
|
3023
|
-
var centerDistance = this.calculateDistance(cluster1.center.lon, cluster1.center.lat, cluster2.center.lon, cluster2.center.lat);
|
|
3024
|
-
var distanceThreshold = this.distanceBetweenClusters;
|
|
3025
|
-
if (centerDistance <= distanceThreshold) {
|
|
3026
|
-
// Merge clusters.
|
|
3027
|
-
(_a = cluster1.points).push.apply(_a, cluster2.points);
|
|
3028
|
-
mergedClusters.splice(j, 1);
|
|
3029
|
-
this.removeClusterEntity(cluster2.center.id);
|
|
3030
|
-
mergeOccurred = true;
|
|
3031
|
-
break;
|
|
3032
|
-
}
|
|
3033
|
-
}
|
|
3034
|
-
if (mergeOccurred) {
|
|
3035
|
-
break;
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
return mergedClusters;
|
|
3250
|
+
return { clusters: validClusters, noLongerClustered: noLongerClustered };
|
|
3040
3251
|
};
|
|
3041
3252
|
/**
|
|
3042
3253
|
* Removes Cesium cluster entity.
|
|
@@ -3064,24 +3275,7 @@
|
|
|
3064
3275
|
PointClustering.prototype.addPoint = function (id, cartesian3) {
|
|
3065
3276
|
var point = this.convertCartesianToCartographic(cartesian3);
|
|
3066
3277
|
point.id = id;
|
|
3067
|
-
this.quadTree.Insert(point);
|
|
3068
|
-
};
|
|
3069
|
-
/**
|
|
3070
|
-
* Calculates rough distance across earth between two points.
|
|
3071
|
-
* @param lon1
|
|
3072
|
-
* @param lat1
|
|
3073
|
-
* @param lon2
|
|
3074
|
-
* @param lat2
|
|
3075
|
-
* @returns
|
|
3076
|
-
*/
|
|
3077
|
-
PointClustering.prototype.calculateDistance = function (lon1, lat1, lon2, lat2) {
|
|
3078
|
-
var lonDelta = Math.abs(lon1 - lon2);
|
|
3079
|
-
var latDelta = Math.abs(lat1 - lat2);
|
|
3080
|
-
// Approximate radius of the Earth in kilometers
|
|
3081
|
-
var earthRadius = 6371;
|
|
3082
|
-
var distance = 2 * Math.asin(Math.sqrt(Math.sin(latDelta / 2) * Math.sin(latDelta / 2) +
|
|
3083
|
-
Math.cos(lat1) * Math.cos(lat2) * Math.sin(lonDelta / 2) * Math.sin(lonDelta / 2))) * earthRadius;
|
|
3084
|
-
return distance;
|
|
3278
|
+
return this.quadTree.Insert(point);
|
|
3085
3279
|
};
|
|
3086
3280
|
/**
|
|
3087
3281
|
* Adds entity to clustering logic.
|
|
@@ -3105,14 +3299,14 @@
|
|
|
3105
3299
|
return false;
|
|
3106
3300
|
}
|
|
3107
3301
|
if (!this.pointColorBg && entity.point) {
|
|
3108
|
-
|
|
3109
|
-
if (
|
|
3302
|
+
var pointColorBg = GetValue$1(this.viewer, entity.point.color);
|
|
3303
|
+
if (pointColorBg) {
|
|
3110
3304
|
var cColor = null;
|
|
3111
|
-
if (
|
|
3112
|
-
cColor = new Cesium.Color(
|
|
3305
|
+
if (pointColorBg instanceof Object) {
|
|
3306
|
+
cColor = new Cesium.Color(pointColorBg.red, pointColorBg.green, pointColorBg.blue, pointColorBg.alpha);
|
|
3113
3307
|
}
|
|
3114
|
-
else if (typeof
|
|
3115
|
-
cColor = Cesium.Color.fromCssColorString(
|
|
3308
|
+
else if (typeof pointColorBg === "string") {
|
|
3309
|
+
cColor = Cesium.Color.fromCssColorString(pointColorBg);
|
|
3116
3310
|
}
|
|
3117
3311
|
// Determine if text color should instead be black based on background.
|
|
3118
3312
|
// cColor contains r,g,b,a values where r,g,b are in the range [0,1].
|
|
@@ -3124,11 +3318,21 @@
|
|
|
3124
3318
|
else {
|
|
3125
3319
|
this.pointColorTxt = "white";
|
|
3126
3320
|
}
|
|
3321
|
+
this.pointColorBg = cColor.toCssColorString();
|
|
3127
3322
|
}
|
|
3128
3323
|
}
|
|
3129
3324
|
}
|
|
3325
|
+
if (!this.iconUrl && entity.billboard) {
|
|
3326
|
+
var iconUrl = GetValue$1(this.viewer, entity.billboard.image);
|
|
3327
|
+
if (typeof iconUrl == "string") {
|
|
3328
|
+
this.iconUrl = iconUrl;
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
var added = this.addPoint(id, pos3d);
|
|
3332
|
+
if (!added) {
|
|
3333
|
+
return false;
|
|
3334
|
+
}
|
|
3130
3335
|
this.registeredEntityIds.add(id);
|
|
3131
|
-
this.addPoint(id, pos3d);
|
|
3132
3336
|
this.updateQueue.Call();
|
|
3133
3337
|
return true;
|
|
3134
3338
|
};
|
|
@@ -10608,7 +10812,7 @@
|
|
|
10608
10812
|
ViewRenderEngine.Render = Render;
|
|
10609
10813
|
})(exports.ViewRenderEngine || (exports.ViewRenderEngine = {}));
|
|
10610
10814
|
|
|
10611
|
-
var VERSION = "2.
|
|
10815
|
+
var VERSION = "2.2.0";
|
|
10612
10816
|
|
|
10613
10817
|
exports.VERSION = VERSION;
|
|
10614
10818
|
exports.CesiumViewMonitor = CesiumViewMonitor;
|