【超图】SuperMap iClient3D for Cesium点聚合更改图标样式

发布于:2022-11-03 ⋅ 阅读:(618) ⋅ 点赞:(0)

作者:taco

        最近有客户要做点聚合的功能,本身cesium自带聚合的方法,而且之前有人写过类似的方法。可以参考这篇文章SuperMap iClient3D for WebGL之点聚合_supermapsupport的博客-CSDN博客nannan       在场景中查询结果通常以标记点(布告板)的形式展现,但是如果标记点较多,不仅会大大增加客户端的渲染时间,让客户端变得很卡,而且会让人产生密集恐惧症(图1)。                     .https://blog.csdn.net/supermapsupport/article/details/111868209        但是发现聚合只能用Cesium内定的默认符号,并不能自定义符号。如果使用了本地图片呢?那上面的数字就会消失掉。

						var pinimg='./images/location4.png';
						 cluster.billboard.image = pinimg;

这样并不能满足我们实际的需求,因为我们还需要上面的数字。当然,如果不需要的话也可以直接替换。这样我们就需要查接口是否能带数字替换了。然而PinBuilder却接口表示“我没有”。

都是固定好了的,根本改不了。要不就是有样式改不了字,要不就是有字改不了样式。这时候万能的百度还是给出了答案。有人看了开源cesium的代码,底层是可以改的。实现方式看这篇文章。主要思路就是用Canvas对象重新绘制图片。

/**
 * @description: 将图片和文字合成新图标使用(参考Cesium源码)
 * @param {*} url:图片地址
 * @param {*} label:文字
 * @param {*} size:画布大小
 * @return {*} 返回canvas
 */
function combineIconAndLabel(url, label, size) {
    // 创建画布对象
    let canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;

    let ctx = canvas.getContext("2d");

    let promise = new Cesium.Resource.fetchImage(url).then(image => {
        // 异常判断
        try {
            ctx.drawImage(image, 0, 0);
        } catch (e) {
            console.log(e);
        }
        
        // 渲染字体
        // font属性设置顺序:font-style, font-variant, font-weight, font-size, line-height, font-family
        ctx.fillStyle = Cesium.Color.WHITE.toCssColorString();
        ctx.font = 'bold 20px Microsoft YaHei';
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(label, size / 2, size / 2);

        return canvas;
    });
    return promise;
}

完整代码:

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<title>聚合</title>
		<link href="../../Build/Cesium/Widgets/widgets.css" rel="stylesheet">
		<link href="./css/pretty.css" rel="stylesheet">
		<script type="text/javascript" src="./js/jquery.min.js"></script>
		<script src="./js/config.js"></script>
		<script src="./js/tooltip.js"></script>
		<script src="./js/spectrum.js"></script>
		<script type="text/javascript" src="./SampleData/test.js"></script>
		<script type="text/javascript" src="../../Build/Cesium/Cesium.js"></script>
	</head>

	<body>
		<div id="cesiumContainer"></div>
		<div class="params-setting-container">
			<div class="params-setting-anchor" title="显示/隐藏参数面板"><span class="fui-expand"></span></div>
			<div class="params-setting">
				<button id="start" class="button black">点选旋转</button>
				<button id="sqltest" class="button black">叠加过滤rest</button>
				<div class="param-item">
					<label for="bloomShow">开启泛光</label>
					<input type="checkbox" id="bloomShow">
				</div>
				<div class="param-item">
					<label>亮度阈值</label>
					<input type="range" id="bloom-threshold" min="0" max="1" value="1" step="0.1" style="width: 140px">
				</div>
				<div class="param-item">
					<label>泛光强度</label>
					<input type="range" id="bloom-intensity" min="0" max="10" value="1" step="0.1" style="width: 140px">
				</div>
				<div class="param-item">
					<label for="hdrShow">开启HDR</label>
					<input type="checkbox" id="hdrShow">
				</div>
				<div class="param-item">
					<label for="startNight">开启夜景</label>
					<input type="checkbox" id="startNight">
				</div>
			</div>
		</div>
		<script>
			var viewer = new Cesium.Viewer('cesiumContainer');
			viewer.scene.globe.depthTestAgainstTerrain = false;
			console.log(ss)
			var subtest = ss.sub;
			console.log(subtest)
			var scene = viewer.scene;

			var clusteringlayer = new Cesium.CustomDataSource('clusteringlayer');

			viewer.dataSources.add(clusteringlayer);

			for (var i = 0; i < subtest.length; i++) {
				let x = parseFloat(subtest[i].centerx);
				let y = parseFloat(subtest[i].centery);
				let name = subtest[i].proname;
				console.log(name, x, y)
				clusteringlayer.entities.add({
					position: Cesium.Cartesian3.fromDegrees(x, y, 100),
					billboard: {
						image: './images/p.png',
						scale: 0.1
					}
				})

			}

			var pixelRange = 20;
			var minimumClusterSize = 5;
			var enabled = true;
			//启用集群
			clusteringlayer.clustering.enabled = enabled;

			//设置扩展屏幕空间边界框的像素范围。
			clusteringlayer.clustering.pixelRange = pixelRange;
			//可以群集的最小屏幕空间对象
			clusteringlayer.clustering.minimumClusterSize = minimumClusterSize;
			//将进行实体的广告牌聚类
			clusteringlayer.clustering.clusterBillboards = true;
			customStyle();

			var removeListener;
			//自定义地图图钉生成为画布元素
			var pinBuilder = new Cesium.PinBuilder();
			var aa = null;

			function customStyle() {
				if (Cesium.defined(removeListener)) {
					removeListener();
					removeListener = undefined;
				} else {
					removeListener = clusteringlayer.clustering.clusterEvent.addEventListener(function(clusteredEntities,
						cluster) {

						cluster.label.show = false;
						cluster.billboard.show = true;
						cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;


						if (clusteredEntities.length >= 20) {
							cluster.billboard.image = combineIconAndLabel('./images/zs_redz.png', clusteredEntities
								.length, 64);
							cluster.billboard.width = 72;
							cluster.billboard.height = 72;
						} else if (clusteredEntities.length >= 12) {
							cluster.billboard.image = combineIconAndLabel('./images/zs_redz.png', clusteredEntities
								.length, 64);
							cluster.billboard.width = 56;
							cluster.billboard.height = 56;
						} else if (clusteredEntities.length >= 8) {
							cluster.billboard.image = combineIconAndLabel('./images/zs_redz.png', clusteredEntities
								.length, 64);
							cluster.billboard.width = 48;
							cluster.billboard.height = 48;
						} else {
							cluster.billboard.image = combineIconAndLabel('./images/zs_redz.png', clusteredEntities
								.length, 64);
							cluster.billboard.width = 40;
							cluster.billboard.height = 40;
						}
					});
				}
			}
			
			function combineIconAndLabel(url, label, size) {
				// 创建画布对象
				let canvas = document.createElement('canvas');
				canvas.width = size;
				canvas.height = size;
			
				let ctx = canvas.getContext("2d");
			
				let promise = new Cesium.Resource.fetchImage(url).then(image => {
					// 异常判断
					try {
						ctx.drawImage(image, 0, 0);
					} catch (e) {
						console.log(e);
					}
			
					// 渲染字体
					// font属性设置顺序:font-style, font-variant, font-weight, font-size, line-height, font-family
					ctx.fillStyle = Cesium.Color.WHITE.toCssColorString();
					ctx.font = 'bold 20px Microsoft YaHei';
					ctx.textAlign = "center";
					ctx.textBaseline = "middle";
					ctx.fillText(label, size / 5, size / 4);
			
					return canvas;
				});
				return promise;
			}
		</script>
	</body>

</html>

 这样我们就完成了自定义样式以及文字

 

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到