使用cesium绘制飞行路线,开始飞行,暂停飞行,继续飞行、退出飞行
token记得换成您自己的!!!
申请cesium的token 官网【Cesium: The Platform for 3D Geospatial】
<template>
<div>
<div class="container">
<button class="btnel" type="primary" size="mini" @click="drawLineRoad"
>绘制路线</button
>
<button class="btnel" type="primary" size="mini" @click="startFly"
>开始飞行</button
>
<button class="btnel" type="primary" size="mini" @click="stopFly"
>暂停飞行</button
>
<button class="btnel" type="primary" size="mini" @click="continueFly"
>继续飞行</button
>
<button class="btnel" type="primary" size="mini" @click="exitFly"
>退出飞行</button
>
</div>
<div id="cesiumContainer"></div>
</div>
</template>
<script>
import * as Cesium from 'cesium';
// import Cesium from 'cesium/Cesium'
// import * as Cesium from "cesium";
// import 'cesium/Widgets/widgets.css'
export default {
name: 'CesiumViewer',
data() {
return {
// TerrionUrl: '/3D-stk_terrain/rest/realspace/datas/info/data/path',
viewer: null,
marks: [
{ lng: 108.9423344082, lat: 34.2609052589, height: 6000, flytime: 1 },
{ lng: 116.812948, lat: 36.550064, height: 1000, flytime: 1 },
// height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒)
{ lng: 116.812948, lat: 36.560064, height: 1000, flytime: 1 },
{ lng: 116.802948, lat: 36.560064, height: 1000, flytime: 1 },
{ lng: 116.802948, lat: 36.550064, height: 1000, flytime: 1 },
],
marksIndex: 1,
pitchValue: -90,
changeCameraTime: 5,
flytime: 30,
Exection: {},
handler: {},
activeShapePoints: [],
floatingPoint: undefined,
activeShape: undefined,
drawingMode: 'line',
};
},
mounted() {
//保证模型初始化
Cesium.Ion.defaultAccessToken =
'您自己的token';
// const vtxfTerrainProvider = new Cesium.CesiumTerrainProvider({
// url: this.TerrionUrl,
// requestVertexNormals: true
// });
this.viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly: true,
selectionIndicator: false,
// baseLayerPicker: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
// fullscreenButton: false,
// terrainProvider: vtxfTerrainProvider,
selectionIndicator: false,
infoBox: false,
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer',
// enablePickFeatures: false,
}),
// terrainProvider: Cesium.createWorldTerrain()
terrainProvider: new Cesium.CesiumTerrainProvider({
url: 'http://data.marsgis.cn/terrain',
}),
});
//双击鼠标左键清除默认事件
this.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
// this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
// url: "/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
// }));
this.viewer._cesiumWidget._creditContainer.style.display = 'none'; //隐藏logo版权
let destination = Cesium.Cartesian3.fromDegrees(116.3974, 39.9087, 10000); // 北京天安门广场的经纬度坐标及高度
this.viewer.camera.flyTo({
destination: destination,
duration: 2, // 飞行动画持续时间(单位:秒)
});
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
// this.initFly();
},
methods: {
initFly() {
const { viewer, marks } = this;
// eslint-disable-next-line no-unused-vars
const self = this;
viewer.scene.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
marks[0].lng,
marks[0].lat,
marks[0].height
), //定位坐标点,建议使用谷歌地球坐标位置无偏差
duration: 1, //定位的时间间隔
});
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
},
flyExtent() {
const { viewer, marks, pitchValue } = this;
const self = this;
// 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
const pitch = Cesium.Math.toRadians(pitchValue);
// 时间间隔2秒钟
this.setExtentTime(marks[this.marksIndex].flytime);
this.Exection = function TimeExecution() {
let preIndex = self.marksIndex - 1;
if (self.marksIndex == 0) {
preIndex = marks.length - 1;
}
//计算俯仰角
let heading = self.bearing(
marks[preIndex].lat,
marks[preIndex].lng,
marks[self.marksIndex].lat,
marks[self.marksIndex].lng
);
heading = Cesium.Math.toRadians(heading);
// 当前已经过去的时间,单位s
const delTime = Cesium.JulianDate.secondsDifference(
viewer.clock.currentTime,
viewer.clock.startTime
);
const originLat =
self.marksIndex == 0
? marks[marks.length - 1].lat
: marks[self.marksIndex - 1].lat;
const originLng =
self.marksIndex == 0
? marks[marks.length - 1].lng
: marks[self.marksIndex - 1].lng;
const endPosition = Cesium.Cartesian3.fromDegrees(
originLng +
((marks[self.marksIndex].lng - originLng) /
marks[self.marksIndex].flytime) *
delTime,
originLat +
((marks[self.marksIndex].lat - originLat) /
marks[self.marksIndex].flytime) *
delTime,
marks[self.marksIndex].height
);
viewer.scene.camera.setView({
destination: endPosition,
orientation: {
heading: heading,
pitch: pitch,
},
});
if (
Cesium.JulianDate.compare(
viewer.clock.currentTime,
viewer.clock.stopTime
) >= 0
) {
viewer.clock.onTick.removeEventListener(self.Exection);
//有个转向的功能
self.changeCameraHeading();
}
};
viewer.clock.onTick.addEventListener(self.Exection);
},
// 相机原地定点转向
changeCameraHeading() {
const { viewer, marks, pitchValue, changeCameraTime } = this;
const self = this;
let { marksIndex } = this;
let nextIndex = this.marksIndex + 1;
if (marksIndex == marks.length - 1) {
nextIndex = 0;
}
// 计算两点之间的方向
const heading = this.bearing(
marks[marksIndex].lat,
marks[marksIndex].lng,
marks[nextIndex].lat,
marks[nextIndex].lng
);
// 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
const pitch = Cesium.Math.toRadians(pitchValue);
// 给定飞行一周所需时间,比如10s, 那么每秒转动度数
const angle =
(heading - Cesium.Math.toDegrees(viewer.camera.heading)) /
changeCameraTime;
// 时间间隔2秒钟
this.setExtentTime(changeCameraTime);
// 相机的当前heading
const initialHeading = viewer.camera.heading;
this.Exection = function TimeExecution() {
// 当前已经过去的时间,单位s
const delTime = Cesium.JulianDate.secondsDifference(
viewer.clock.currentTime,
viewer.clock.startTime
);
const heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;
viewer.scene.camera.setView({
orientation: {
heading: heading,
pitch: pitch,
},
});
if (
Cesium.JulianDate.compare(
viewer.clock.currentTime,
viewer.clock.stopTime
) >= 0
) {
viewer.clock.onTick.removeEventListener(self.Exection);
self.marksIndex =
++self.marksIndex >= marks.length ? 0 : self.marksIndex;
if (self.marksIndex != 0) {
self.flyExtent();
}
}
};
viewer.clock.onTick.addEventListener(self.Exection);
},
// 设置飞行的时间到viewer的时钟里
setExtentTime(time) {
const { viewer } = this;
const startTime = Cesium.JulianDate.fromDate(new Date());
const stopTime = Cesium.JulianDate.addSeconds(
startTime,
time,
new Cesium.JulianDate()
);
viewer.clock.startTime = startTime.clone(); // 开始时间
viewer.clock.stopTime = stopTime.clone(); // 结速时间
viewer.clock.currentTime = startTime.clone(); // 当前时间
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式-达到终止时间后停止
viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。
},
/** 相机视角飞行 结束 **/
/** 飞行时 camera的方向调整(heading) 开始 **/
// 角度转弧度
toRadians(degrees) {
return (degrees * Math.PI) / 180;
},
// 弧度转角度
toDegrees(radians) {
return (radians * 180) / Math.PI;
},
//计算俯仰角
bearing(startLat, startLng, destLat, destLng) {
startLat = this.toRadians(startLat);
startLng = this.toRadians(startLng);
destLat = this.toRadians(destLat);
destLng = this.toRadians(destLng);
let y = Math.sin(destLng - startLng) * Math.cos(destLat);
let x =
Math.cos(startLat) * Math.sin(destLat) -
Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
let brng = Math.atan2(y, x);
let brngDgr = this.toDegrees(brng);
return (brngDgr + 360) % 360;
},
/** 飞行时 camera的方向调整(heading) 结束 **/
/**绘制路线 */
drawLineRoad() {
const { handler, viewer, activeShapePoints } = this;
const self = this;
//鼠标左键
handler.setInputAction(function (event) {
var earthPosition = viewer.scene.pickPosition(event.position);
if (Cesium.defined(earthPosition)) {
if (activeShapePoints.length === 0) {
self.floatingPoint = self.createPoint(earthPosition);
activeShapePoints.push(earthPosition);
var dynamicPositions = new Cesium.CallbackProperty(function () {
return activeShapePoints;
}, false);
self.activeShape = self.drawShape(dynamicPositions); //绘制动态图
}
activeShapePoints.push(earthPosition);
self.createPoint(earthPosition);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动
handler.setInputAction(function (event) {
if (Cesium.defined(self.floatingPoint)) {
var newPosition = viewer.scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
self.floatingPoint.position.setValue(newPosition);
activeShapePoints.pop();
activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(function () {
self.terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
},
// Redraw the shape so it's not dynamic and remove the dynamic shape.
terminateShape() {
const { activeShapePoints, viewer, flytime } = this;
activeShapePoints.pop(); //去除最后一个动态点
if (activeShapePoints.length) {
this.marks = [];
for (const position of activeShapePoints) {
const latitude = this.toDegrees(
Cesium.Cartographic.fromCartesian(position).latitude
);
const longitude = this.toDegrees(
Cesium.Cartographic.fromCartesian(position).longitude
);
this.marks.push({
lat: latitude,
lng: longitude,
flytime,
height: 200,
});
}
this.drawShape(activeShapePoints); //绘制最终图
}
viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点)
viewer.entities.remove(this.activeShape); //去除动态图形
this.floatingPoint = undefined;
this.activeShape = undefined;
this.activeShapePoints = [];
},
//绘制点
createPoint(worldPosition) {
var point = this.viewer.entities.add({
position: worldPosition,
point: {
color: Cesium.Color.WHITE,
pixelSize: 1,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
return point;
},
//初始化为线
drawShape(positionData) {
const { drawingMode, viewer } = this;
var shape;
if (drawingMode === 'line') {
shape = viewer.entities.add({
// polyline: {
// positions: positionData,
// clampToGround: true,
// with:3
// },
polyline: {
width: 17,
// ...lineStyle,
// material: new Cesium.PolylineOutlineMaterialProperty({
// color: Cesium.Color.AQUA.withAlpha(0.7), // 线的颜色
// outlineWidth: 4,
// outlineColor: Cesium.Color.WHITE.withAlpha(0.6),
// }),
material: new Cesium.PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString('#FF0000') //transparent
),
show: true,
clampToGround: true,
positions: positionData,
},
});
}
return shape;
},
//开始飞行
startFly() {
const { Exection } = this;
if (Object.keys(Exection).length > 0) {
this.exitFly();
}
this.flyExtent();
},
//停止飞行
stopFly() {
this.viewer.clock.shouldAnimate = false;
},
//继续飞行
continueFly() {
this.viewer.clock.shouldAnimate = true;
},
//退出飞行
exitFly() {
const { Exection, viewer, marks, pitchValue } = this;
viewer.clock.onTick.removeEventListener(Exection);
// 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
const pitch = Cesium.Math.toRadians(pitchValue);
const marksIndex = 1;
let preIndex = marksIndex - 1;
//计算俯仰角
let heading = this.bearing(
marks[preIndex].lat,
marks[preIndex].lng,
marks[marksIndex].lat,
marks[marksIndex].lng
);
heading = Cesium.Math.toRadians(heading);
const endPosition = Cesium.Cartesian3.fromDegrees(
marks[0].lng,
marks[0].lat,
marks[0].height
);
viewer.scene.camera.setView({
destination: endPosition,
orientation: {
heading: heading,
pitch: pitch,
},
});
},
},
created() {},
};
</script>
<style lang="scss" scoped>
.container {
position: absolute;
z-index: 9999;
margin-top: 20px;
.btnel {
min-width: 100px;
text-align: center;
padding: 10px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
border-radius: 5px;
margin-left: 10px;
cursor: pointer;
}
}
</style>