基于百度地图api绘制台风轨迹(1)

该代码示例展示了如何利用百度地图API创建一个地图应用,初始化地图,设置中心点和缩放级别,并绘制台风的移动轨迹。通过定义一系列经纬度坐标点,创建Polyline对象表示台风路径,并用不同等级的图标表示台风强度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于百度地图api绘制台风轨迹(1)

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>绘制台风路径</title>
	<script src="http://api.map.baidu.com/api?v=2.0&ak=TxwfD55mIGhS3brtR4UP1hMnZLUB3mV9"></script>
	<style type="text/css">
		html,body,#allmap{
			height:100%;
			margin:0;
			overflow:hidden;
			font-family:"微软雅黑";
		}
	</style>
</head>
<body>
	<div id="allmap"></div>
	<script type="text/javascript">
		//初始化地图
		var map = new BMap.Map("allmap");
		map.centerAndZoom(new BMap.Point(121.5, 25.0), 4); //设置地图中心点和缩放级别
		map.enableScrollWheelZoom(); //启用滚轮缩放

		//定义台风路径数据
		var lats = [22.1,23.4,24.7,26.2,27.9,29.7,31.3,32.8,34.0,34.7,35.1,35.1];
		var lons = [120.6,122.3,124.0,125.2,126.1,127.1,128.1,129.0,129.9,130.3,130.3,129.9];
		var grades = [2,2,2,2,2,2,2,2,2,2,2,2];

		//绘制台风路径
		var points = [];
		for (var i = 0; i < lats.length; i++) {
			points.push(new BMap.Point(lons[i], lats[i]));
		}
		var polyline = new BMap.Polyline(points, {strokeColor:"#FF0000", strokeWeight:5}); //定义折线对象
		map.addOverlay(polyline); //添加折线到地图中

		//添加台风等级图例
		var icon1 = new BMap.Icon("http://api.map.baidu.com/img/markers.png",new BMap.Size(23, 25),{offset:new BMap.Size(10, 25),imageOffset:new BMap.Size(0, 0)});
		var marker1 = new BMap.Marker(new BMap.Point(lons[lons.length-1],lats[lats.length-1]),{icon:icon1});
		marker1.setTitle("等级:"+grades[grades.length-1]);
		map.addOverlay(marker1);
	</script>
</body>
</html>

在这里插入图片描述

<think>我们将在Vue2项目中使用Cesium实现台风轨迹展示效果。主要功能包括: 1. 动态轨迹台风路径的动画效果(如粒子流动或动态移动的台风图标) 2. 位置点标记:在路径上标记台风的位置点 3. 点击弹框:点击台风或标记点时显示台风详细信息 4. 风圈绘制:根据台风强度绘制不同半径的风圈 5. 多台风同时显示:支持同时展示多个台风路径和风圈 步骤: 1. 准备数据:假设我们有多个台风的数据,每个台风包含多个时间点的位置、风速、气压等信息,以及每个时间点的风圈半径(或根据风速计算)。 2. 初始化Cesium Viewer:在Vue组件中创建Cesium Viewer。 3. 绘制台风路径:使用Polyline或PolylineGlow绘制路径,并添加动态效果(如流动材质或粒子系统)。 4. 标记位置点:在路径的关键点(如每6小时)添加点标记。 5. 添加台风图标:在台风当前位置添加一个动态图标(如旋转的台风图标)并随时间移动。 6. 绘制风圈:每个时间点根据风圈半径(或风速计算半径)绘制圆(或椭圆),并随着台风移动而更新。 7. 事件处理:为台风图标或标记点添加点击事件,显示Popup信息框。 8. 多台风处理:循环处理每个台风的数据,分别创建路径、标记、风圈等。 注意:为了性能,我们使用Entity API,并注意在组件销毁时移除所有实体和事件。 参考引用[1]中提到的台风效果,引用[2]中的动态预测路径绘制,引用[3]中的台风范围几何绘制,以及引用[4]中的图层管理思想。 我们将编写一个Vue组件,代码结构如下: 1. 在mounted中初始化Cesium Viewer。 2. 使用watch或方法加载台风数据并渲染。 3. 定义方法绘制单个台风路径、标记点、风圈等。 4. 定义方法实现路径动画(使用Cesium的时间相关函数或自定义动画)。 5. 定义方法显示弹窗。 由于Cesium在Vue2中的使用,我们需要注意在组件销毁时销毁Viewer。 数据格式示例(单个台风): ```json { "name": "台风1", "data": [ { "time": "2023-09-15T08:00:00Z", "lon": 120.0, "lat": 30.0, "windSpeed": 45, // 风速(节) "pressure": 995, // 气压 "radius7": 200, // 7级风圈半径(公里) "radius10": 100 // 10级风圈半径(公里) }, // ... 其他时间点 ] } ``` 我们将为每个台风创建一个Entity集合,并分别管理。 完整代码示例:</think># Vue2 + Cesium 台风轨迹可视化系统 我将为您提供一个完整的Vue2组件,实现类似浙江水利局台风路径展示效果,包含动态轨迹、位置点叠加、点击弹窗及风圈展示功能,并支持多台风同时显示。 ## 核心功能实现思路 1. **动态轨迹动画**:使用Cesium的`SampledPositionProperty`实现路径动画效果 2. **位置点标记**:在关键时间点添加自定义标记 3. **风圈绘制**:根据台风强度绘制不同半径的圆环 4. **信息弹窗**:点击台风时显示详细信息 5. **多台风支持**:使用图层管理实现台风同时显示 ## 完整Vue组件代码 ```html <template> <div class="typhoon-container"> <div class="map-container" ref="cesiumContainer"></div> <div class="control-panel"> <h2>台风路径可视化系统</h2> <div class="typhoon-selector"> <div v-for="(typhoon, index) in typhoons" :key="index" class="typhoon-item"> <input type="checkbox" v-model="typhoon.visible" @change="toggleTyphoon(typhoon)"> <span :style="{color: typhoon.color}">●</span> {{ typhoon.name }} </div> </div> <div class="animation-controls"> <button @click="playAnimation">播放</button> <button @click="pauseAnimation">暂停</button> <button @click="resetAnimation">重置</button> <div class="speed-control"> <label>速度:</label> <input type="range" min="1" max="10" v-model="animationSpeed"> </div> </div> <div v-if="selectedTyphoon" class="info-panel"> <h3>{{ selectedTyphoon.name }} 信息</h3> <p>当前风速: {{ selectedTyphoon.currentWindSpeed }} kt</p> <p>当前气压: {{ selectedTyphoon.currentPressure }} hPa</p> <p>移动速度: {{ selectedTyphoon.movementSpeed }} km/h</p> <p>移动方向: {{ selectedTyphoon.direction }}</p> </div> </div> </div> </template> <script> import * as Cesium from 'cesium'; export default { name: 'TyphoonVisualization', data() { return { viewer: null, typhoons: [], animationSpeed: 3, animationInterval: null, selectedTyphoon: null, currentTimeIndex: 0 }; }, mounted() { this.initCesium(); this.loadTyphoonData(); }, beforeDestroy() { if (this.animationInterval) clearInterval(this.animationInterval); if (this.viewer) this.viewer.destroy(); }, methods: { initCesium() { // 初始化Cesium Viewer Cesium.Ion.defaultAccessToken = 'YOUR_CESIUM_ACCESS_TOKEN'; // 替换为您的token this.viewer = new Cesium.Viewer(this.$refs.cesiumContainer, { terrainProvider: Cesium.createWorldTerrain(), animation: false, timeline: false, geocoder: false, homeButton: false, sceneModePicker: false, baseLayerPicker: false, navigationHelpButton: false, fullscreenButton: false, infoBox: false, selectionIndicator: false }); // 设置初始视图位置(中国东部海域) this.viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(125, 25, 15000000), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: 0.0 } }); // 添加点击事件监听 this.viewer.screenSpaceEventHandler.setInputAction((movement) => { const pickedObject = this.viewer.scene.pick(movement.position); if (Cesium.defined(pickedObject) && pickedObject.id) { this.showTyphoonInfo(pickedObject.id.typhoonData); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, loadTyphoonData() { // 模拟台风数据 - 实际项目中应从API获取 this.typhoons = [ { id: 'typhoon1', name: '台风梅花', color: '#FF5252', visible: true, currentWindSpeed: 45, currentPressure: 965, movementSpeed: 25, direction: '西北', positions: [ { time: '2023-09-01T00:00:00Z', lon: 135.0, lat: 18.0, windSpeed: 35, pressure: 980, radius7: 250, radius10: 120 }, { time: '2023-09-02T00:00:00Z', lon: 132.5, lat: 20.5, windSpeed: 40, pressure: 975, radius7: 280, radius10: 150 }, { time: '2023-09-03T00:00:00Z', lon: 130.0, lat: 23.0, windSpeed: 45, pressure: 965, radius7: 300, radius10: 180 }, { time: '2023-09-04T00:00:00Z', lon: 127.5, lat: 25.5, windSpeed: 50, pressure: 955, radius7: 320, radius10: 200 }, { time: '2023-09-05T00:00:00Z', lon: 125.0, lat: 28.0, windSpeed: 55, pressure: 945, radius7: 350, radius10: 220 } ] }, { id: 'typhoon2', name: '台风木兰', color: '#2196F3', visible: true, currentWindSpeed: 40, currentPressure: 970, movementSpeed: 20, direction: '北', positions: [ { time: '2023-09-01T00:00:00Z', lon: 140.0, lat: 15.0, windSpeed: 30, pressure: 985, radius7: 200, radius10: 100 }, { time: '2023-09-02T00:00:00Z', lon: 138.0, lat: 17.5, windSpeed: 35, pressure: 980, radius7: 220, radius10: 120 }, { time: '2023-09-03T00:00:00Z', lon: 136.0, lat: 20.0, windSpeed: 40, pressure: 970, radius7: 250, radius10: 140 }, { time: '2023-09-04T00:00:00Z', lon: 134.0, lat: 22.5, windSpeed: 45, pressure: 960, radius7: 280, radius10: 160 }, { time: '2023-09-05T00:00:00Z', lon: 132.0, lat: 25.0, windSpeed: 50, pressure: 950, radius7: 300, radius10: 180 } ] } ]; // 初始化绘制所有台风 this.typhoons.forEach(typhoon => { if (typhoon.visible) { this.drawTyphoon(typhoon); } }); }, drawTyphoon(typhoon) { // 创建台风路径 const positions = typhoon.positions.map(pos => Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat) ); // 绘制路径线 const pathEntity = this.viewer.entities.add({ name: typhoon.name + '路径', polyline: { positions: positions, width: 4, material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.2, color: Cesium.Color.fromCssColorString(typhoon.color) }), clampToGround: true } }); // 添加路径点标记 typhoon.positions.forEach((pos, index) => { const pointEntity = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat), point: { pixelSize: 10, color: Cesium.Color.WHITE, outlineColor: Cesium.Color.fromCssColorString(typhoon.color), outlineWidth: 2 }, label: { text: `${index + 1}`, font: '14px sans-serif', fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(0, -15) }, typhoonData: typhoon }); }); // 添加台风当前位置标记(动态) const positionProperty = new Cesium.SampledPositionProperty(); typhoon.positions.forEach((pos, index) => { const time = Cesium.JulianDate.fromIso8601(pos.time); const position = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat); positionProperty.addSample(time, position); }); typhoon.typhoonEntity = this.viewer.entities.add({ name: typhoon.name, position: positionProperty, billboard: { image: this.getTyphoonIcon(typhoon), width: 48, height: 48, scale: 0.8, rotation: Cesium.Math.toRadians(-45) // 模拟旋转效果 }, typhoonData: typhoon }); // 绘制风圈 const windCircles = []; typhoon.positions.forEach(pos => { const position = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat); // 7级风圈 windCircles.push(this.viewer.entities.add({ position: position, ellipse: { semiMinorAxis: pos.radius7 * 1000, semiMajorAxis: pos.radius7 * 1000, material: Cesium.Color.fromCssColorString(typhoon.color).withAlpha(0.1), outline: true, outlineColor: Cesium.Color.fromCssColorString(typhoon.color).withAlpha(0.5), outlineWidth: 2 }, typhoonData: typhoon })); // 10级风圈 windCircles.push(this.viewer.entities.add({ position: position, ellipse: { semiMinorAxis: pos.radius10 * 1000, semiMajorAxis: pos.radius10 * 1000, material: Cesium.Color.RED.withAlpha(0.1), outline: true, outlineColor: Cesium.Color.RED.withAlpha(0.5), outlineWidth: 2 }, typhoonData: typhoon })); }); typhoon.windCircles = windCircles; }, getTyphoonIcon(typhoon) { // 创建自定义台风图标(实际项目中可以使用图片) const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; const context = canvas.getContext('2d'); // 绘制台风图标 context.beginPath(); context.arc(32, 32, 24, 0, Math.PI * 2); context.fillStyle = typhoon.color; context.fill(); context.beginPath(); context.arc(32, 32, 16, 0, Math.PI * 2); context.fillStyle = '#FFFFFF'; context.fill(); return canvas.toDataURL(); }, toggleTyphoon(typhoon) { if (typhoon.visible) { this.drawTyphoon(typhoon); } else { this.removeTyphoon(typhoon); } }, removeTyphoon(typhoon) { if (typhoon.typhoonEntity) { this.viewer.entities.remove(typhoon.typhoonEntity); } if (typhoon.windCircles) { typhoon.windCircles.forEach(circle => { this.viewer.entities.remove(circle); }); } }, playAnimation() { if (this.animationInterval) clearInterval(this.animationInterval); const startTime = Cesium.JulianDate.fromIso8601(this.typhoons[0].positions[0].time); const stopTime = Cesium.JulianDate.fromIso8601( this.typhoons[0].positions[this.typhoons[0].positions.length - 1].time ); this.viewer.clock.startTime = startTime.clone(); this.viewer.clock.stopTime = stopTime.clone(); this.viewer.clock.currentTime = startTime.clone(); this.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; this.viewer.clock.multiplier = this.animationSpeed; this.viewer.timeline.zoomTo(startTime, stopTime); this.viewer.clock.shouldAnimate = true; }, pauseAnimation() { this.viewer.clock.shouldAnimate = false; }, resetAnimation() { this.viewer.clock.shouldAnimate = false; this.viewer.clock.currentTime = this.viewer.clock.startTime.clone(); }, showTyphoonInfo(typhoon) { this.selectedTyphoon = typhoon; // 高亮显示选中的台风 this.viewer.entities.values.forEach(entity => { if (entity.typhoonData && entity.typhoonData.id === typhoon.id) { if (entity.point) { entity.point.pixelSize = 14; entity.point.outlineWidth = 3; } if (entity.billboard) { entity.billboard.scale = 1.2; } } else if (entity.typhoonData) { if (entity.point) { entity.point.pixelSize = 10; entity.point.outlineWidth = 2; } if (entity.billboard) { entity.billboard.scale = 0.8; } } }); } } }; </script> <style scoped> .typhoon-container { display: flex; height: 100vh; width: 100%; } .map-container { flex: 1; height: 100%; } .control-panel { width: 300px; background: rgba(255, 255, 255, 0.9); padding: 20px; overflow-y: auto; box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1); } .typhoon-selector { margin: 20px 0; } .typhoon-item { margin: 10px 0; padding: 8px; border-radius: 4px; background: #f5f5f5; cursor: pointer; display: flex; align-items: center; } .typhoon-item:hover { background: #e0e0e0; } .typhoon-item span { margin-right: 8px; font-size: 20px; } .animation-controls { display: flex; flex-wrap: wrap; gap: 10px; margin: 20px 0; } .animation-controls button { padding: 8px 16px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; flex: 1; min-width: 70px; } .animation-controls button:hover { background: #1976D2; } .speed-control { display: flex; align-items: center; width: 100%; margin-top: 10px; } .speed-control label { margin-right: 10px; width: 60px; } .speed-control input { flex: 1; } .info-panel { background: #e3f2fd; padding: 15px; border-radius: 4px; margin-top: 20px; border-left: 4px solid #2196F3; } .info-panel h3 { margin-top: 0; color: #0d47a1; } .info-panel p { margin: 8px 0; } </style> ``` ## 关键功能说明 1. **动态轨迹动画**: - 使用`SampledPositionProperty`实现台风移动动画 - 通过Cesium时钟控制动画播放速度 - 支持播放、暂停和重置功能 2. **多台风显示**: - 使用复选框控制每个台风的显示/隐藏 - 每个台风使用不同颜色区分 - 独立管理每个台风路径、标记和风圈 3. **风圈绘制**: - 根据台风数据中的半径参数绘制7级和10级风圈 - 使用半透明填充和轮廓线增强可视化效果 - 风圈随台风位置动态变化 4. **信息交互**: - 点击台风图标或路径点显示详细信息 - 选中的台风会高亮显示 - 右侧面板显示台风详细信息 5. **性能优化**: - 使用图层管理技术避免重复创建实体 - 仅在需要时显示台风要素 - 合理控制动画帧率 ## 使用说明 1. 替换`YOUR_CESIUM_ACCESS_TOKEN`为您的实际Cesium访问令牌 2. 在实际项目中,应从API获取台风数据替换模拟数据 3. 可根据需要调整台风图标样式和风圈颜色 4. 动画速度可通过滑块控制(1-10倍速) ## 相关技术参考 1. Cesium官方文档:[https://cesium.com/learn/cesiumjs/ref-doc/](https://cesium.com/learn/cesiumjs/ref-doc/) 2. Cesium台风可视化示例:[https://sandcastle.cesium.com/](https://sandcastle.cesium.com/) 3. Vue2集成Cesium指南:[https://cesium.com/blog/2019/10/31/integrating-cesium-with-vue/](https://cesium.com/blog/2019/10/31/integrating-cesium-with-vue/) 这个组件提供了完整的台风路径可视化解决方案,您可以将其集成到现有的Vue2项目中,或根据需要进行定制化开发。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值