SuperMap iClient3D for Cesium立体地图选中+下钻特效

在大屏展示系统中,对行政区划数据制作了立体效果,如果希望选中某一行政区划进行重点介绍,目前常见的方式是通过修改选中对象色彩、边线等方式进行实现;这里提供另外一种偏移动效的思路,并提供下钻功能,让地图选中效果更加炫酷,一起开看看如何实现吧!

立体地图选中+下钻特效

一、数据制作

对于上述视频中的立体地图制作,此处不做讲述,如有需要可访问:Online 开发者中心

可视化案例中提供了详细的代码、数据下载链接及数据制作过程。

二、实现思路

选中抬升效果的实现思路如下图所示

点击下钻效果的实现思路如下图所示

三、关键代码

数据抬升关键代码如下:

javascript 复制代码
handlerPoint.setInputAction(function(event) {
					var result = viewer.scene.pick(event.endPosition)
					var layertop = scene.layers.find('sichuan432602');
					var selection = layertop.getSelection();
					if (selection.length > 0) {			
						var selectedId = Number(selection[selection.length - 1]);
						if (!offsetList[selectedId]) {
							offsetList[selectedId] = {
								"isoffset": true,
								"offsetZ": 0
							};
						} else {
							for (let key in offsetList) {
								offsetList[key].isoffset = false;
							}
							offsetList[selectedId].isoffset = true;
						}
					} else {
						for (let key in offsetList) {
							offsetList[key].isoffset = false;
						}
					}
				}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
				setInterval(function() {
					var layertop = scene.layers.find('sichuan432602');
					for (let key in offsetList) {
						if (offsetList[key].isoffset) {
							if (offsetList[key].offsetZ < 20000) {
								offsetList[key].offsetZ = offsetList[key].offsetZ + 1000;
								layertop.setObjsTranslate([key], new Cesium.Cartesian3(0, 0, offsetList[key].offsetZ))
							}


						} else {
							if (offsetList[key].offsetZ > 0) {
								offsetList[key].offsetZ = offsetList[key].offsetZ - 500;
								layertop.setObjsTranslate([key], new Cesium.Cartesian3(0, 0, offsetList[key].offsetZ))
							}
						}
					}

				}, 20)

下钻关键代码如下:

javascript 复制代码
let handlerPoint = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas);
				handlerPoint.setInputAction(function(event){
					viewer.entities.removeById("selectedId");
					
					var layertop = scene.layers.find('sichuan432602');
					var selection = layertop.getSelection();
					if (selection.length > 0) {
						var selectedId = Number(selection[selection.length - 1]);
						// layertop.setObjsVisible([selectedId], true)
						provinceEntity.show = false;
						$("#echarts").hide();
						cityEntity.entities.removeAll();
						cityEntity.show = true;
						layertop.releaseSelection();
						$.ajax({
							url: './images/cbg/sichuancitys4326.json',
							success: function(data) {
								var geometrys = data.features;
								for (var i = 0; i < geometrys.length; i++) {
									if (geometrys[i].properties.cityid != selectedId) {
										continue;
									}
									var geometry = geometrys[i].geometry;
									var coordinates = geometry.coordinates;
									var pipeLinePts = [];
									var polygon;
									if (geometry.type == "MultiLineString") {
										debugger;
									} else {
										for (var j = 0; j < coordinates[0].length; j++) {
											
											var pos = new Cesium.Cartesian3.fromDegrees(Number(coordinates[0][j][0]),
												Number(coordinates[0][j][1]), 20000);
											pipeLinePts.push(pos);
					
										}
										polygon = new Cesium.PolygonHierarchy(pipeLinePts)
									}
					
									cityEntity.entities.add({
										polygon: {
											hierarchy: polygon,
											// outlineWidth: 1/window.devicePixelRatio,
											material: new Cesium.Color(255 / 255, 0 / 255, 0 / 255,
												0),
											outline: true,
											height: 20000,
											outlineWidth: 5 / window.devicePixelRatio,
											outlineColor: new Cesium.Color(170 / 255, 170 / 255,
												170 / 255, 1)
										}
									})
									var position = new Cesium.Cartesian3.fromDegrees(geometrys[i].properties.Center_X,
										geometrys[i].properties.Center_Y, 500);
									cityEntity.entities.add({
										// id: name,
										position: position,
										label: {
											text: geometrys[i].properties.name,
											outlineWidth: 3,
											style: Cesium.LabelStyle.FILL_AND_OUTLINE,
											fillColor: new Cesium.Color(255 / 255, 255 / 255, 255 /
												255, 0.9),
											outlineColor: new Cesium.Color(0 / 255, 18 / 255, 4 /
												255, 1.0),
											disableDepthTestDistance: Number.POSITIVE_INFINITY,
											font: 14 - Math.pow(window.devicePixelRatio, 2) +
												'px Arial bold',
											pixelOffset: new window.Cesium.Cartesian2(15 * name
												.length + 15, 0)
										}
									})
								}
								viewer.flyTo(cityEntity, {
									duration: 1.5,
									offset: {
										heading: 0.04200358377266422, // 以弧度为单位的航向角。
										pitch: -0.6718486685836051, // 以弧度为单位的俯仰角。
										range: 0 // 到中心的距离,以米为单位。								
									}
								});
					
							}
						});
					
					} else {
						provinceEntity.show = true;
						cityEntity.show = false;
						$("#echarts").show();
					}
				},Cesium.ScreenSpaceEventType.LEFT_CLICK)

四、示例完整代码

示例完整代码如下:

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
		<meta name="viewport"
			content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
		<title>四川省蓝色风格影像地图</title>
		<link href="../../Build/Cesium/Widgets/widgets.css" rel="stylesheet">
		<link href="./css/pretty.css" rel="stylesheet">
		<script type="text/javascript" src="./js/bubble/popup.js"></script>
		<script src="./js/jquery.min.js"></script>
		<script src="./js/config.js"></script>
		<script src="./js/echarts.min.js"></script>
		<script src="./js/EchartsLayer.js"></script>
		<script type="text/javascript" src="../../Build/Cesium/Cesium.js"></script>
		<style>
			#test3 .divpoint {
				background: url(./images/qipao2.png) no-repeat;
				background-size: cover;
				width: 230px;
				height: 150px;
			}

			#test3 .label-wrap {
				padding-left: 100px;
				padding-top: 8px;
				box-sizing: border-box;
			}

			#test3 .data-li {
				font-size: 14px;
				margin-top: 6px;
			}

			.sm-div-graphic {
				position: absolute;
				color: #fff;
				font-size: 14px;
			}
		</style>
	</head>
	<body>
		<div id="cesiumContainer">
		</div>
		<div id='loadingbar' class="spinner">
			<div class="spinner-container container1">
				<div class="circle1"></div>
				<div class="circle2"></div>
				<div class="circle3"></div>
				<div class="circle4"></div>
			</div>
			<div class="spinner-container container2">
				<div class="circle1"></div>
				<div class="circle2"></div>
				<div class="circle3"></div>
				<div class="circle4"></div>
			</div>
			<div class="spinner-container container3">
				<div class="circle1"></div>
				<div class="circle2"></div>
				<div class="circle3"></div>
				<div class="circle4"></div>
			</div>
		</div>
		<!-- <div id="test3" class="sm-div-graphic" style="pointer-events: all; display: block;  z-index: 8920788;">
			<div class="divpoint divpoint-theme-29baf1">
				<div class="label-wrap">
					<div id="name" class="pop-title">移动的弹窗</div>
					<div class="label-content">
						<div class="data-li">
							<div id="renkou" class="data-label">速度:10km/h</div>
						</div>
						<div class="data-li">
							<div id="gdp" class="data-label">目的地:xxxx</div>
						</div>
					</div>
				</div>
			</div>
		</div> -->
		<script type="text/javascript">
			function onload(Cesium) {
				var sichuanGDP = {};
				//初始化viewer部件,并添加天地图服务
				var xres = parseInt(window.screen.width * window.devicePixelRatio);
				var yres = parseInt(window.screen.height * window.devicePixelRatio);
				viewer = new Cesium.Viewer('cesiumContainer', {
					baseLayerPicker: false,
					orderIndependentTranslucency: false,
					shouldAnimate: true,
					infoBox: false,
					contextOptions: {
						webgl: {
							alpha: true
						},
						maxDrawingBufferWidth: xres,
						maxDrawingBufferHeight: yres
					},
				});
				var provinceEntity = new window.Cesium.CustomDataSource("provinceEntity");
				viewer.dataSources.add(provinceEntity);
				var cityEntity = new window.Cesium.CustomDataSource("cityEntity");
				viewer.dataSources.add(cityEntity);
				cityEntity.show = false;
				var echartsLayer;
				viewer.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({
					url: './images/cbg/world06.jpg',
				}));
				viewer.resolutionScale = window.devicePixelRatio;
				viewer.useBrowserRecommendedResolution = true;
				viewer.scene.globe.depthTestAgainstTerrain = false;
				viewer.scene.terrainProvider.isCreateSkirt = false;
				var scene = viewer.scene;
				scene.screenSpaceCameraController.zoomFactor = 5.0;
				scene.lightSource.ambientLightColor = new Cesium.Color(0.5, 0.5, 0.5, 1);
				var widget = viewer.cesiumWidget;
				$('#loadingbar').remove();
				try {
					var promise = viewer.scene.open("http://localhost:8090/iserver/services/3D-sichuanblue/rest/realspace")

				} catch (e) {
					if (widget._showRenderLoopErrors) {
						var title = '渲染时发生错误,已停止渲染。';
						widget.showErrorPanel(title, undefined, e);
					}
				}
				$.ajax({
					url: './images/cbg/sichuanfenjie4326.json',
					success: function(data) {
						var geometrys = data.features;
						for (var i = 0; i < geometrys.length; i++) {
							var geometry = geometrys[i].geometry;
							var coordinates = geometry.coordinates;
							var pipeLinePts = [];
							for (var j = 0; j < coordinates.length; j++) {
								var convertPos = new Cesium.Cartesian3.fromDegrees(coordinates[j][0], coordinates[j][
									1
								], 500);
								pipeLinePts.push(convertPos);
							}
							provinceEntity.entities.add({
								polyline: {
									positions: pipeLinePts,
									width: 2 / window.devicePixelRatio,
									material: new Cesium.Color(94 / 255, 213 / 255, 245 / 255, 0.5),
									arcType: Cesium.ArcType.RHUMB,
									clampToGround: true
								}
							})
						}
					}
				});
				$.ajax({
					url: './images/cbg/sichuanbounds4326.json',
					success: function(data) {
						var geometrys = data.features;
						for (var i = 0; i < geometrys.length; i++) {
							var geometry = geometrys[i].geometry;
							var coordinates = geometry.coordinates;
							var pipeLinePts = [];
							for (var j = 0; j < coordinates.length; j++) {

								var convertPos = new Cesium.Cartesian3.fromDegrees(coordinates[j][0], coordinates[j][
									1
								], 500);
								pipeLinePts.push(convertPos);
							}
							provinceEntity.entities.add({
								polyline: {
									positions: pipeLinePts,
									width: 2.5,
									material: new Cesium.Color(94 / 255, 213 / 255, 245 / 255, 1)
								}
							})
						}
					}
				});
				var position = new Cesium.Cartesian3.fromDegrees(109.40543308511627, 26.993328925156895, -50000);


				var targetPosition = new Cesium.Cartesian3.fromDegrees(101.98226836938083, 24.519626362055106, -50000);


				var options_n = {
					targetPosition: targetPosition,
					color: new Cesium.Color(255 / 255, 255 / 255, 255 / 255, 1),
					intensity: 3,
				};
				var directionalLight_n = new Cesium.DirectionalLight(position, options_n);
				// viewer.scene.addLightSource(directionalLight_n);
				addPOIeChart();

				function addPOIeChart() {
					var data = [];
					var geoCoordMap = {};
					$.ajax({
						url: './images/cbg/sichuan_city_name_P_2.json',
						success: function(datas) {
							let realtimeDataEntities = []
							var geometrys = datas.features;
							for (var i = 0; i < geometrys.length; i++) {
								var geometry = geometrys[i].geometry;
								var coordinates = geometry.coordinates;
								var name = geometrys[i].properties.name;
								if (name.length > 4) {
									var tempname = "";
									for (var k = 0; k < name.length; k++) {
										tempname = tempname + name[k] + "\n"
									}
									name = tempname;
								}
								var level = Number(geometrys[i].properties.level) - 1;

								data.push({
									'name': name,
									'value': 220 + level * 150
								})
								geoCoordMap[name] = [coordinates[0], coordinates[1]];;
								var convertposition = new Cesium.Cartesian3.fromDegrees(coordinates[0], coordinates[
									1], 500);
								sichuanGDP[geometrys[i].properties.UserID] = {
									"coordinates": convertposition,
									"name": geometrys[i].properties.name2,
									"renkou": geometrys[i].properties.renkou,
									"gdp": geometrys[i].properties.gdp,

								}
								provinceEntity.entities.add({
									// id: name,
									position: convertposition,
									label: {
										text: name,
										outlineWidth: 3,
										style: Cesium.LabelStyle.FILL_AND_OUTLINE,
										fillColor: name === "成都市" ? new Cesium.Color(240 / 255, 255 / 255,
											0 /
											255, 1) : new Cesium.Color(255 / 255, 255 / 255, 255 / 255,
											0.9),
										outlineColor: name === "成都市" ? new Cesium.Color(0 / 255, 18 / 255,
											4 /
											255, 1) : new Cesium.Color(79 / 255, 128 / 255, 169 / 255,
											0.9),
										disableDepthTestDistance: Number.POSITIVE_INFINITY,
										font: 14 + level * 8 - Math.pow(window.devicePixelRatio, 2) +
											'px Arial bold',
										pixelOffset: name.length > 4 ? new window.Cesium.Cartesian2(-25, 0) :
											new window.Cesium.Cartesian2(40 + level * 15, 0)
									}
								})


							}
							const convertData = function(data) {
								const res = [];
								for (let i = 0; i < data.length; i++) {
									const geoCoord = geoCoordMap[data[i].name];
									if (geoCoord) {
										res.push({
											name: data[i].name,
											value: geoCoord.concat(data[i].value)
										});
									}
								}
								return res;
							};
							const options = {
								animation: !1,
								GLMap: {},
								series: [{
									name: '前5',
									type: 'effectScatter',
									coordinateSystem: 'GLMap',
									data: convertData(data.sort(function(a, b) {
										return b.value - a.value;
									}).slice(0, 50)),
									symbolSize: function(val) {
										return val[2] / 20;
									},
									showEffectOn: 'render',
									rippleEffect: {
										brushType: 'stroke',
										period: 1.5,
										scale: 3.5
									},
									hoverAnimation: true,
									itemStyle: {
										normal: {
											color: '#FFFFFF',
											shadowBlur: 20,
											shadowColor: '#333'
										}
									},
									zlevel: 1
								}]
							};
							echartsLayer = new EchartsLayer(viewer);
							echartsLayer.chart.setOption(options);
						}
					});
				}
				let handlerPoint = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas);
				handlerPoint.setInputAction(function(event){
					viewer.entities.removeById("selectedId");
					
					var layertop = scene.layers.find('sichuan432602');
					var selection = layertop.getSelection();
					if (selection.length > 0) {
						var selectedId = Number(selection[selection.length - 1]);
						// layertop.setObjsVisible([selectedId], true)
						provinceEntity.show = false;
						$("#echarts").hide();
						cityEntity.entities.removeAll();
						cityEntity.show = true;
						layertop.releaseSelection();
						$.ajax({
							url: './images/cbg/sichuancitys4326.json',
							success: function(data) {
								var geometrys = data.features;
								for (var i = 0; i < geometrys.length; i++) {
									if (geometrys[i].properties.cityid != selectedId) {
										continue;
									}
									var geometry = geometrys[i].geometry;
									var coordinates = geometry.coordinates;
									var pipeLinePts = [];
									var polygon;
									if (geometry.type == "MultiLineString") {
										debugger;
									} else {
										for (var j = 0; j < coordinates[0].length; j++) {
											
											var pos = new Cesium.Cartesian3.fromDegrees(Number(coordinates[0][j][0]),
												Number(coordinates[0][j][1]), 20000);
											pipeLinePts.push(pos);
					
										}
										polygon = new Cesium.PolygonHierarchy(pipeLinePts)
									}
					
									cityEntity.entities.add({
										polygon: {
											hierarchy: polygon,
											// outlineWidth: 1/window.devicePixelRatio,
											material: new Cesium.Color(255 / 255, 0 / 255, 0 / 255,
												0),
											outline: true,
											height: 20000,
											outlineWidth: 5 / window.devicePixelRatio,
											outlineColor: new Cesium.Color(170 / 255, 170 / 255,
												170 / 255, 1)
										}
									})
									var position = new Cesium.Cartesian3.fromDegrees(geometrys[i].properties.Center_X,
										geometrys[i].properties.Center_Y, 500);
									cityEntity.entities.add({
										// id: name,
										position: position,
										label: {
											text: geometrys[i].properties.name,
											outlineWidth: 3,
											style: Cesium.LabelStyle.FILL_AND_OUTLINE,
											fillColor: new Cesium.Color(255 / 255, 255 / 255, 255 /
												255, 0.9),
											outlineColor: new Cesium.Color(0 / 255, 18 / 255, 4 /
												255, 1.0),
											disableDepthTestDistance: Number.POSITIVE_INFINITY,
											font: 14 - Math.pow(window.devicePixelRatio, 2) +
												'px Arial bold',
											pixelOffset: new window.Cesium.Cartesian2(15 * name
												.length + 15, 0)
										}
									})
								}
								viewer.flyTo(cityEntity, {
									duration: 1.5,
									offset: {
										heading: 0.04200358377266422, // 以弧度为单位的航向角。
										pitch: -0.6718486685836051, // 以弧度为单位的俯仰角。
										range: 0 // 到中心的距离,以米为单位。								
									}
								});
					
							}
						});
					
					} else {
						provinceEntity.show = true;
						cityEntity.show = false;
						$("#echarts").show();
					}
				},Cesium.ScreenSpaceEventType.LEFT_CLICK)
				
				
				var offsetList = {};
				handlerPoint.setInputAction(function(event) {
					var result = viewer.scene.pick(event.endPosition)
					var layertop = scene.layers.find('sichuan432602');
					var selection = layertop.getSelection();
					if (selection.length > 0) {			
						var selectedId = Number(selection[selection.length - 1]);
						if (!offsetList[selectedId]) {
							offsetList[selectedId] = {
								"isoffset": true,
								"offsetZ": 0
							};
						} else {
							for (let key in offsetList) {
								offsetList[key].isoffset = false;
							}
							offsetList[selectedId].isoffset = true;
						}
					} else {
						for (let key in offsetList) {
							offsetList[key].isoffset = false;
						}
					}
				}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
				setInterval(function() {
					var layertop = scene.layers.find('sichuan432602');
					for (let key in offsetList) {
						if (offsetList[key].isoffset) {
							if (offsetList[key].offsetZ < 20000) {
								offsetList[key].offsetZ = offsetList[key].offsetZ + 1000;
								layertop.setObjsTranslate([key], new Cesium.Cartesian3(0, 0, offsetList[key].offsetZ))
							}


						} else {
							if (offsetList[key].offsetZ > 0) {
								offsetList[key].offsetZ = offsetList[key].offsetZ - 500;
								layertop.setObjsTranslate([key], new Cesium.Cartesian3(0, 0, offsetList[key].offsetZ))
							}
						}
					}

				}, 20)

			}
			if (typeof Cesium !== 'undefined') {
				window.startupCalled = true;
				onload(Cesium);
			}
		</script>
	</body>
</html>
相关推荐
头茬韭菜几秒前
第 3 篇:「Pydantic 即 Schema」—— 工具生态三层解剖
前端·chrome·ai·openmanus
恋猫de小郭21 分钟前
Flutter 状态管理基准测评,一个很有趣的观点
android·前端·flutter
雪芽蓝域zzs27 分钟前
前端编辑组件wangEditor
前端
风骏时光牛马1 小时前
稳定性治理及疑难问题深度剖析与实战复盘
前端
JeffongTan9 小时前
在LWC中镶嵌VF Page获取用户IP
前端·javascript·salesforce
陆枫Larry11 小时前
Astro 是什么
前端
是立不是利13 小时前
写给设计师的 CSS 博客美学指南
前端·css
默_笙14 小时前
🏝 Docker 就是"房地产开发":从施工图纸到小区物业的容器化指南
前端·javascript
计算机魔术师14 小时前
Rohan Paul 谈用时间跨度衡量智能体能力,并引用 OpenAI 自动化研究实习生里程碑
前端