1151 lines
36 KiB
Vue
1151 lines
36 KiB
Vue
<template>
|
||
<div>
|
||
<div id="path-viewer"></div>
|
||
<div class="path-container" >
|
||
<div class="fly-box">
|
||
<div class="fly-title">
|
||
<label>飞行漫游</label>
|
||
<i class="el-icon-close" @click="close"></i>
|
||
</div>
|
||
<div class="fly-content">
|
||
<div class="fly-tab-path" v-show="!showCoord">
|
||
<div class="fly-operation">
|
||
<button @click="addPath">
|
||
<i class="el-icon-circle-plus-outline"></i>新增路线
|
||
</button>
|
||
<button @click="document.getElementById('importBtn').click()">
|
||
导入
|
||
</button>
|
||
<input
|
||
type="file"
|
||
style="display: none"
|
||
name="导入"
|
||
id="importBtn"
|
||
accept=".json"
|
||
@change="importPath"
|
||
/>
|
||
<button @click="clearDraw">清除</button>
|
||
</div>
|
||
<div class="fly-table">
|
||
<table>
|
||
<thead class="fly-table-header">
|
||
<tr>
|
||
<th
|
||
style="width: 150px; text-align: left; padding-left: 10px"
|
||
>
|
||
名称
|
||
</th>
|
||
<th style="text-align: center">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="fly-table-body">
|
||
<tr v-for="p in paths" :key="p.id">
|
||
<td @dblclick.stop="enableInput">
|
||
<input
|
||
v-model="p.name"
|
||
disabled
|
||
@blur="inptBlur(p.id, $event)"
|
||
/>
|
||
</td>
|
||
<td class="fly-table-operation">
|
||
<i
|
||
title="漫游"
|
||
v-show="!p.playing"
|
||
@click.stop="flyPath(p.id)"
|
||
class="el-icon-s-promotion"
|
||
></i>
|
||
<i
|
||
title="暂停"
|
||
v-show="p.playing"
|
||
@click.stop="stopFly(p.id)"
|
||
class="el-icon-video-pause"
|
||
></i>
|
||
<i
|
||
title="编辑"
|
||
@click.stop="editPath(p.id)"
|
||
class="el-icon-edit-outline"
|
||
></i>
|
||
<i
|
||
title="删除"
|
||
@click.stop="deletePath(p.id)"
|
||
class="el-icon-delete"
|
||
></i>
|
||
<i
|
||
title="导出"
|
||
@click.stop="exportPath(p.id)"
|
||
class="el-icon-printer"
|
||
></i>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div
|
||
v-show="!paths.length"
|
||
style="height: 80px; text-align: center"
|
||
>
|
||
<i
|
||
class="el-icon-folder-delete"
|
||
style="font-size: 2rem; margin: 20px 0 10px"
|
||
></i>
|
||
<div>暂无数据</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="fly-tab-coord" v-show="showCoord">
|
||
<div class="title-box">
|
||
<label>路线名称:{{ currPath.name }}</label>
|
||
</div>
|
||
<div class="fly-coord-content">
|
||
<div
|
||
class="path-coord"
|
||
v-for="(item, index) in currPath.coords"
|
||
:key="index"
|
||
>
|
||
<label>第 {{ index + 1 }} 个点</label>
|
||
<table>
|
||
<tr>
|
||
<td style="width: 120px; text-align: center">经度</td>
|
||
<td><input v-model.number="item[0]" /></td>
|
||
</tr>
|
||
<tr>
|
||
<td style="width: 120px; text-align: center">纬度</td>
|
||
<td><input v-model.number="item[1]" /></td>
|
||
</tr>
|
||
<tr>
|
||
<td style="width: 120px; text-align: center">高度</td>
|
||
<td><input v-model.number="item[2]" /></td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="coord-btn">
|
||
<button @click="changPath">确定</button>
|
||
<button @click="showCoord = false">取消</button>
|
||
</div>
|
||
</div>
|
||
<!--<div class="fly-tabs">-->
|
||
<!--<label class="fly-tabs-item">轨迹</label>-->
|
||
<!--<label class="fly-tabs-item">坐标</label>-->
|
||
<!--</div>-->
|
||
</div>
|
||
<div class="handle handle-l"></div>
|
||
<div class="handle handle-r"></div>
|
||
<div class="handle handle-t"></div>
|
||
<div class="handle handle-b"></div>
|
||
<div class="handle handle-lb"></div>
|
||
<div class="handle handle-rb"></div>
|
||
</div>
|
||
<div
|
||
id="tooltip"
|
||
style="
|
||
position: fixed;
|
||
display: none;
|
||
z-index: 999;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
color: rgb(255, 255, 255);
|
||
font-size: 12px;
|
||
padding: 5px;
|
||
border-radius: 5px;
|
||
"
|
||
>
|
||
左键点击选点,右键也可取消
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
// 对Date的扩展,将 Date 转化为指定格式的String
|
||
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
|
||
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
|
||
// 例子:
|
||
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
|
||
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
|
||
Date.prototype.Format = function (fmt) { //author: meizz
|
||
var o = {
|
||
"M+": this.getMonth() + 1, //月份
|
||
"d+": this.getDate(), //日
|
||
"h+": this.getHours(), //小时
|
||
"m+": this.getMinutes(), //分
|
||
"s+": this.getSeconds(), //秒
|
||
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||
"S": this.getMilliseconds() //毫秒
|
||
};
|
||
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||
for (var k in o)
|
||
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||
return fmt;
|
||
}
|
||
// import { cartesianToLnglat, uuid } from "./js/cUtils";
|
||
export default {
|
||
data() {
|
||
return {
|
||
name: "轨迹播放(第一人称视角)",
|
||
showCoord: false,
|
||
|
||
tableData: [],
|
||
isAddStatus: false,
|
||
pointPositionList: [], //点位置坐标数组
|
||
pointEntities: [],
|
||
polylineEntities: [],
|
||
playing: false,
|
||
// handler:new Cesium.ScreenSpaceEventHandler(viewer.canvas),//事件实例
|
||
pathVisible: true,
|
||
|
||
// tempPoints:[],//存储绘制的点
|
||
// isAddPoint:false,//是否新增加了点,需要更新
|
||
// tempEntities:[],//存储绘制轨迹中产生的实体(点、线)
|
||
paths: [], //路径集合,{id:'',name,'',coords:[]}
|
||
currPath: {
|
||
id: "dsdad",
|
||
name: "未命名-124230",
|
||
coords: [
|
||
[112, 32, 2],
|
||
[112.2, 32.1, 2],
|
||
[112.2, 32.1, 2],
|
||
[112.2, 32.1, 2],
|
||
[112.2, 32.1, 2],
|
||
[112.2, 32.1, 2],
|
||
],
|
||
},
|
||
currId: "", //记录当前绘制的轨迹Id
|
||
};
|
||
},
|
||
mounted() {
|
||
this.initCesium();
|
||
// let Cesium = this.$cesium;
|
||
window.pointEntities = [];
|
||
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //事件实例
|
||
// 创建轨迹实体数据源
|
||
window.pathSource = new Cesium.CustomDataSource("pathSource");
|
||
viewer.dataSources.add(window.pathSource);
|
||
// 获取本地存储的轨迹数据
|
||
let localPath = JSON.parse(localStorage.getItem("localPaths"));
|
||
this.palyPath = localPath ? localPath : [];
|
||
},
|
||
methods: {
|
||
cartesianToLnglat:(cartesian)=>{
|
||
// //笛卡尔空间坐标转WGS84弧度.
|
||
// const ellipsoid84 = Cesium.Ellipsoid.wgs84;
|
||
// const cartographicPosition = ellipsoid84.cartesianToCartographic(cartesian);
|
||
const cartographicPosition = Cesium.Cartographic.fromCartesian(cartesian);
|
||
|
||
return [
|
||
Cesium.Math.toDegrees(cartographicPosition.longitude),
|
||
Cesium.Math.toDegrees(cartographicPosition.latitude),
|
||
]
|
||
},
|
||
uuid:function(len, radix) {
|
||
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
||
var uuid = [], i;
|
||
radix = radix || chars.length;
|
||
if (len) {
|
||
// Compact form
|
||
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
|
||
} else {
|
||
// rfc4122, version 4 form
|
||
var r;
|
||
// rfc4122 requires these characters
|
||
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
|
||
uuid[14] = '4';
|
||
// Fill in random data. At i==19 set the high bits of clock sequence as
|
||
// per rfc4122, sec. 4.1.5
|
||
for (i = 0; i < 36; i++) {
|
||
if (!uuid[i]) {
|
||
r = 0 | Math.random() * 16;
|
||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
|
||
}
|
||
}
|
||
}
|
||
return uuid.join('');
|
||
},
|
||
initCesium() {
|
||
let box = document.getElementsByClassName("content__default")[0];
|
||
box.style.maxWidth = "100%";
|
||
box.style.paddingTop = 0;
|
||
|
||
let Cesium = this.$cesium;
|
||
window.CESIUM_BASE_URL = "/cesium";
|
||
Cesium.Ion.defaultAccessToken =
|
||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ZjRjNTZkNC01NDYxLTRhMjQtOGEwZC1kZjA3YzQ5YTJlZDkiLCJpZCI6MjYwODQsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODcxOTMwODN9.prGsSKyAW_9Ow5zHYPhbm3LsQL-ApQw5-5PNJkDaHi8";
|
||
var viewer = new Cesium.Viewer("path-viewer", {
|
||
geocoder: false, //位置查找
|
||
homeButton: false, //视图返回初始位置
|
||
sceneModePicker: false, //视角选择器
|
||
baseLayerPicker: false, //底图选择器
|
||
navigationHelpButton: false, //导航帮助按钮
|
||
animation: false, //动画控制器
|
||
creditContainer: document.createElement("div"), //版权显示
|
||
timeline: false, //时间线
|
||
fullscreenButton: false, //全屏控件
|
||
vrButton: false,
|
||
skyBox: false,
|
||
infoBox: false,
|
||
selectionIndicator: false,
|
||
shouldAnimate: false, // Enable animations
|
||
timeline: true, //时间线
|
||
imageryProvider:new Cesium.UrlTemplateImageryProvider({
|
||
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
|
||
minimumLevel: 3,
|
||
maximumLevel: 18
|
||
})
|
||
});
|
||
// var imageryLayers = viewer.scene.imageryLayers;
|
||
// let tdtLayer =
|
||
// imageryLayers.addImageryProvider(tdtLayer);
|
||
|
||
viewer.camera.flyTo({
|
||
destination: new Cesium.Cartesian3(
|
||
-2325771.0288233184,
|
||
5392181.511762224,
|
||
2484480.395134067
|
||
),
|
||
orientation: {
|
||
heading: 6.0399326,
|
||
pitch: -0.30503,
|
||
roll: 6.2825747,
|
||
},
|
||
});
|
||
|
||
window.viewer = viewer;
|
||
window.Cesium = Cesium;
|
||
},
|
||
close() {
|
||
this.isAddStatus = false;
|
||
this.playing = false;
|
||
window.pathSource.entities.removeAll();
|
||
viewer.clock.shouldAnimate = false;
|
||
viewer.trackedEntity = null;
|
||
// this.setFly(false);
|
||
},
|
||
triggerImport() {
|
||
let importBtn = document.getElementById("importBtn").click();
|
||
importBtn.click();
|
||
},
|
||
|
||
inptBlur(id, e) {
|
||
this.paths.forEach((p) => {
|
||
if (p.id == id && !p.name) {
|
||
p.name = "未命名";
|
||
}
|
||
});
|
||
e.currentTarget.disabled = true;
|
||
localStorage.setItem("localPaths", JSON.stringify(this.paths));
|
||
},
|
||
enableInput(e) {
|
||
let inputDom = e.currentTarget.getElementsByTagName("input")[0];
|
||
inputDom.disabled = false;
|
||
inputDom.focus();
|
||
},
|
||
importPath(e) {
|
||
const file = e.target.files[0];
|
||
if (file.type !== "application/json") {
|
||
layer.msg("仅允许上传json文件!");
|
||
return;
|
||
}
|
||
// 执行后清空input的值,防止下次选择同一个文件不会触发onchange事件
|
||
e.target.value = "";
|
||
// 执行读取json数据操作
|
||
const reader = new FileReader();
|
||
reader.readAsText(file); // 读取的结果还有其他读取方式,我认为text最为方便
|
||
reader.onerror = (err) => {
|
||
layer.msg("json文件解析失败!", err);
|
||
};
|
||
|
||
reader.onload = () => {
|
||
const resultData = reader.result;
|
||
if (resultData) {
|
||
try {
|
||
const importData = JSON.parse(resultData);
|
||
this.$set(this.paths, this.paths.length, importData);
|
||
// 更新本地的 paths
|
||
localStorage.setItem("localPaths", JSON.stringify(this.paths));
|
||
layer.msg("导入成功!", { icon: 1, time: 1000 });
|
||
} catch (error) {
|
||
layer.msg("读取数据解析失败!", error);
|
||
}
|
||
} else {
|
||
layer.msg("读取数据解析失败!", error);
|
||
}
|
||
};
|
||
},
|
||
exportPath(id) {
|
||
let path = this.paths.filter((p) => p.id == id)[0];
|
||
let data = JSON.stringify(path, undefined, 4);
|
||
var blob = new Blob([data], { type: "text/json" }),
|
||
e = document.createEvent("MouseEvents"),
|
||
a = document.createElement("a");
|
||
a.download = path.name + ".json";
|
||
a.href = window.URL.createObjectURL(blob);
|
||
a.dataset.downloadurl = ["text/json", a.download, a.href].join(":");
|
||
e.initMouseEvent(
|
||
"click",
|
||
true,
|
||
false,
|
||
window,
|
||
0,
|
||
0,
|
||
0,
|
||
0,
|
||
0,
|
||
false,
|
||
false,
|
||
false,
|
||
false,
|
||
0,
|
||
null
|
||
);
|
||
a.dispatchEvent(e);
|
||
},
|
||
deletePath(id) {
|
||
this.paths = this.paths.filter((p) => p.id != id);
|
||
// 更新本地的 paths
|
||
localStorage.setItem("localPaths", JSON.stringify(this.paths));
|
||
if (this.currId == id) {
|
||
window.pathSource.entities.removeAll();
|
||
}
|
||
},
|
||
editPath(id) {
|
||
this.showCoord = true;
|
||
let path = this.paths.filter((p) => p.id == id)[0];
|
||
this.currPath = { ...path };
|
||
},
|
||
changPath() {
|
||
this.showCoord = false;
|
||
// 更新
|
||
localStorage.setItem("localPaths", JSON.stringify(this.paths));
|
||
console.log(this.currPath);
|
||
},
|
||
clearDraw() {
|
||
window.pathSource.entities.removeAll();
|
||
if (this.handler) {
|
||
this.handler.destroy();
|
||
}
|
||
},
|
||
addPath() {
|
||
// 清空绘制的路径
|
||
window.pathSource.entities.removeAll();
|
||
|
||
let that = this;
|
||
let tempPoints = []; //保存点的集合
|
||
let isAddPoint = false; //是否添加了点
|
||
let tempEntities = []; //用来保存路径上的点实体和线实体
|
||
|
||
// viewer.scene.globe.depthTestAgainstTerrain = true;// 开启深度检测
|
||
document.getElementById("path-viewer").style.cursor = "crosshair";
|
||
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //事件实例
|
||
this.handler = handler;
|
||
//鼠标移动事件
|
||
handler.setInputAction( (movement)=> {
|
||
let tooltip = document.getElementById("tooltip");
|
||
tooltip.style.display = "block";
|
||
tooltip.style.left = movement.endPosition.x + 80 + "px";
|
||
tooltip.style.top = movement.endPosition.y + "px";
|
||
let car3 = viewer.scene.pickPosition(movement.endPosition);
|
||
|
||
//当鼠标在一些Entity上时,car3会是undefined
|
||
if (tempPoints.length > 0 && Cesium.defined(car3)) {
|
||
let carto = this.cartesianToLnglat(car3);
|
||
if (!window.lineEntity || isAddPoint) {
|
||
isAddPoint = false;
|
||
console.log([...tempPoints, [...carto, 8]]);
|
||
window.lineEntity &&
|
||
window.pathSource.entities.remove(window.lineEntity);
|
||
window.lineEntity = that.drawPolyline([
|
||
...tempPoints,
|
||
[...carto, 8],
|
||
]);
|
||
}
|
||
let positions = window.lineEntity.polyline.positions.getValue();
|
||
|
||
positions[positions.length - 1].x = car3.x;
|
||
positions[positions.length - 1].y = car3.y;
|
||
positions[positions.length - 1].z = car3.z;
|
||
window.lineEntity.polyline.positions = new Cesium.CallbackProperty(
|
||
function () {
|
||
return positions;
|
||
},
|
||
false
|
||
);
|
||
}
|
||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||
//左键点击操作
|
||
handler.setInputAction( (click)=> {
|
||
isAddPoint = true;
|
||
//调用获取位置信息的接口
|
||
let ray = viewer.camera.getPickRay(click.position);
|
||
let position = viewer.scene.globe.pick(ray, viewer.scene);
|
||
|
||
//将笛卡尔三维坐标转为地图坐标(弧度)
|
||
var cartographic =
|
||
viewer.scene.globe.ellipsoid.cartesianToCartographic(position);
|
||
var lat_String = Cesium.Math.toDegrees(cartographic.latitude).toFixed(
|
||
6
|
||
);
|
||
var log_String = Cesium.Math.toDegrees(cartographic.longitude).toFixed(
|
||
6
|
||
);
|
||
tempPoints.push([Number(log_String), Number(lat_String), 8]);
|
||
|
||
// tempPoints.push(position);
|
||
let tempLength = tempPoints.length;
|
||
//调用绘制点的接口
|
||
let point = that.drawPoint(tempPoints[tempLength - 1]);
|
||
tempEntities.push(point);
|
||
if (tempLength > 1) {
|
||
let pointline = that.drawPolyline([
|
||
tempPoints[tempPoints.length - 2],
|
||
tempPoints[tempPoints.length - 1],
|
||
]);
|
||
tempEntities.push(pointline);
|
||
} else {
|
||
// tooltip.innerHTML = "请绘制下一个点,右键结束";
|
||
}
|
||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
//右键点击操作
|
||
handler.setInputAction( (click) =>{
|
||
that.currId = this.uuid(8);
|
||
that.$set(that.paths, that.paths.length, {
|
||
id: that.currId,
|
||
name: "未命名-" + new Date().Format("hhmmss"),
|
||
coords: [...tempPoints],
|
||
playing: false,
|
||
});
|
||
// 将轨迹数据保存到本地的 localStorage 中
|
||
localStorage.setItem("localPaths", JSON.stringify(that.paths));
|
||
tempPoints = [];
|
||
handler.destroy(); //关闭事件句柄
|
||
handler = null;
|
||
window.pathSource.entities.remove(window.lineEntity);
|
||
window.lineEntity = null;
|
||
let tooltip = document.getElementById("tooltip");
|
||
tooltip.style.display = "none";
|
||
document.getElementById("path-viewer").style.cursor = "default";
|
||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||
},
|
||
drawPoint(coords, config) {
|
||
let config_ = config ? config : {};
|
||
return window.pathSource.entities.add({
|
||
name: "点几何对象",
|
||
// position: position,
|
||
position: Cesium.Cartesian3.fromDegrees(
|
||
coords[0],
|
||
coords[1],
|
||
coords[2]
|
||
),
|
||
point: {
|
||
color: Cesium.Color.SKYBLUE,
|
||
pixelSize: 10,
|
||
outlineColor: Cesium.Color.YELLOW,
|
||
outlineWidth: 3,
|
||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||
},
|
||
});
|
||
},
|
||
drawPolyline(positions, config_) {
|
||
if (positions.length < 1) return;
|
||
let config = config_ ? config_ : {};
|
||
return window.pathSource.entities.add({
|
||
name: "线几何对象",
|
||
polyline: {
|
||
// positions: positions,
|
||
positions: new Cesium.CallbackProperty(function () {
|
||
return Cesium.Cartesian3.fromDegreesArrayHeights(positions.flat(3));
|
||
}, false),
|
||
width: config.width ? config.width : 5.0,
|
||
material: new Cesium.PolylineGlowMaterialProperty({
|
||
color: config.color
|
||
? new Cesium.Color.fromCssColorString(config.color)
|
||
: Cesium.Color.GOLD,
|
||
}),
|
||
depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
|
||
color: config.color
|
||
? new Cesium.Color.fromCssColorString(config.color)
|
||
: Cesium.Color.GOLD,
|
||
}),
|
||
// clampToGround: true,
|
||
},
|
||
});
|
||
},
|
||
// clearPath(){
|
||
// if(window.entity){
|
||
// viewer.entities.remove(window.entity);
|
||
// }
|
||
// window.pointEntities.forEach(entity=>{
|
||
// viewer.entities.remove(entity);
|
||
// });
|
||
// window.pointEntities = [];
|
||
// this.pointPositionList=[];
|
||
// },
|
||
stopFly(id) {
|
||
// 获取轨迹对象
|
||
let path = this.paths.filter((p) => p.id == id)[0];
|
||
path.playing = false;
|
||
window.pathSource.show = true;
|
||
viewer.trackedEntity = null;
|
||
viewer.clock.shouldAnimate = false;
|
||
},
|
||
flyPath(id) {
|
||
this.currId = id;
|
||
// 获取轨迹对象
|
||
let path = this.paths.filter((p) => p.id == id)[0];
|
||
let coords = path.coords;
|
||
// 清空绘制的路径
|
||
window.pathSource.entities.removeAll();
|
||
// 设置时间
|
||
this.initTimeline(coords.length - 1);
|
||
// 设置坐标的时间,使用 SampledPositionProperty进行插值
|
||
let positions = this.getPositionProperty(coords);
|
||
let orientation = new Cesium.VelocityOrientationProperty(positions);
|
||
|
||
// 创建轨迹实体
|
||
!window.flyEntity && (window.flyEntity = {});
|
||
let flyEntity = window.pathSource.entities.add({
|
||
show: true,
|
||
//Set the entity availability to the same interval as the simulation time.
|
||
availability: new Cesium.TimeIntervalCollection([
|
||
new Cesium.TimeInterval({
|
||
start: this.start,
|
||
stop: this.stop,
|
||
}),
|
||
]),
|
||
//使用计算的位置
|
||
position: positions,
|
||
//Automatically compute orientation based on position movement.
|
||
orientation: orientation,
|
||
//Load the Cesium plane model to represent the entity
|
||
model: {
|
||
show: true,
|
||
uri: "/assets/region/models/CesiumAir/Cesium_Air.glb",
|
||
minimumPixelSize: 64,
|
||
},
|
||
path: {
|
||
resolution: 1,
|
||
material: new Cesium.PolylineGlowMaterialProperty({
|
||
glowPower: 0.1,
|
||
color: Cesium.Color.YELLOW,
|
||
}),
|
||
width: 10,
|
||
},
|
||
});
|
||
window.flyEntity[id] = flyEntity;
|
||
|
||
//监听时间变化,【关键代码】。保存返回值,是一个移除事件的回调函数
|
||
this.tickCallBack && this.tickCallBack();
|
||
this.tickCallBack = viewer.clock.onTick.addEventListener((e) => {
|
||
if (viewer.clock.shouldAnimate === true) {
|
||
let ori = orientation.getValue(viewer.clock.currentTime); //获取偏向角
|
||
let center = positions.getValue(viewer.clock.currentTime); //获取位置
|
||
let transform = Cesium.Matrix4.fromRotationTranslation(
|
||
Cesium.Matrix3.fromQuaternion(ori),
|
||
center
|
||
); //将偏向角转为3*3矩阵,利用实时点位转为4*4矩阵
|
||
viewer.camera.lookAtTransform(
|
||
transform,
|
||
new Cesium.Cartesian3(-10, 0, 0)
|
||
); //将相机向后面放一点
|
||
}
|
||
});
|
||
// 修改飞行状态
|
||
path.playing = true;
|
||
// 飞行的时候隐藏轨迹相关的实体
|
||
window.pathSource.show = false;
|
||
viewer.trackedEntity = window.flyEntity[id];
|
||
viewer.clock.shouldAnimate = true;
|
||
},
|
||
hidePath() {
|
||
this.pathVisible = !this.pathVisible;
|
||
if (window.entity) {
|
||
window.entity.show = this.pathVisible;
|
||
}
|
||
window.pointEntities.forEach((entity) => {
|
||
entity.show = this.pathVisible;
|
||
});
|
||
},
|
||
initTimeline(len) {
|
||
var start = Cesium.JulianDate.fromDate(new Date("2022-10-9"));
|
||
var stop = Cesium.JulianDate.addSeconds(
|
||
start,
|
||
len,
|
||
new Cesium.JulianDate()
|
||
);
|
||
this.start = start;
|
||
this.stop = stop;
|
||
//Make sure viewer is at the desired time.
|
||
viewer.clock.startTime = start.clone();
|
||
viewer.clock.stopTime = stop.clone();
|
||
viewer.clock.currentTime = start.clone();
|
||
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
|
||
viewer.clock.multiplier = 0.06;
|
||
//Set timeline to simulation bounds
|
||
viewer.timeline.zoomTo(start, stop);
|
||
viewer.clock.shouldAnimate = false;
|
||
},
|
||
getPositionProperty(coords) {
|
||
// 给轨迹点关联时间和插值
|
||
const property = new Cesium.SampledPositionProperty();
|
||
for (var i = 0; i < coords.length; i++) {
|
||
var time = Cesium.JulianDate.addSeconds(
|
||
this.start,
|
||
i,
|
||
new Cesium.JulianDate()
|
||
);
|
||
var position = Cesium.Cartesian3.fromDegrees(
|
||
coords[i][0],
|
||
coords[i][1],
|
||
coords[i][2]
|
||
);
|
||
property.addSample(time, position);
|
||
window.pathSource.entities.add({
|
||
position: position,
|
||
point: {
|
||
color: Cesium.Color.SKYBLUE,
|
||
pixelSize: 10,
|
||
outlineColor: Cesium.Color.YELLOW,
|
||
outlineWidth: 3,
|
||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||
},
|
||
});
|
||
}
|
||
return property;
|
||
},
|
||
readyPath() {
|
||
// 给轨迹点关联时间和插值
|
||
const property = new Cesium.SampledPositionProperty();
|
||
property.setInterpolationOptions({
|
||
interpolationDegree: 5,
|
||
interpolationAlgorithm: Cesium.HermitePolynomialApproximation, //设置插值算法
|
||
});
|
||
for (var i = 0; i < this.pointPositionList.length; i++) {
|
||
var time = Cesium.JulianDate.addSeconds(
|
||
this.start,
|
||
i,
|
||
new Cesium.JulianDate()
|
||
);
|
||
var position = Cesium.Cartesian3.fromArray(this.pointPositionList[i]);
|
||
property.addSample(time, position);
|
||
}
|
||
this.position = property;
|
||
this.orientation = new Cesium.VelocityOrientationProperty(property);
|
||
},
|
||
createModel() {
|
||
//Actually create the entity
|
||
if (window.entity) {
|
||
viewer.entities.remove(window.entity);
|
||
window.entity = null;
|
||
}
|
||
window.entity = viewer.entities.add({
|
||
//Set the entity availability to the same interval as the simulation time.
|
||
availability: new Cesium.TimeIntervalCollection([
|
||
new Cesium.TimeInterval({
|
||
start: this.start,
|
||
stop: this.stop,
|
||
}),
|
||
]),
|
||
//Use our computed positions
|
||
position: this.position,
|
||
//Automatically compute orientation based on position movement.
|
||
orientation: this.orientation,
|
||
model: {
|
||
uri: "./models/CesiumAir/Cesium_Air.glb",
|
||
minimumPixelSize: 64,
|
||
show: false,
|
||
},
|
||
//Show the path as a pink line sampled in 1 second increments.
|
||
path: {
|
||
resolution: 10,
|
||
material: new Cesium.PolylineGlowMaterialProperty({
|
||
width: 30,
|
||
// glowPower: 0.1,
|
||
color: Cesium.Color.fromCssColorString("rgba(230,163,60,1)"),
|
||
}),
|
||
width: 10,
|
||
},
|
||
});
|
||
// window.entity = entity;
|
||
//追踪物体
|
||
// viewer.trackedEntity = entity;
|
||
},
|
||
palyPath() {
|
||
this.playing = !this.playing;
|
||
viewer.trackedEntity = this.playing ? window.entity : null;
|
||
viewer.clock.shouldAnimate = this.playing;
|
||
},
|
||
handlerPath() {
|
||
this.isAddStatus = !this.isAddStatus;
|
||
if (this.isAddStatus) {
|
||
// 清空坐标点
|
||
(this.pointPositionList = []), //点位置坐标数组
|
||
(window.pointEntities = []),
|
||
this.registerEvent();
|
||
} else {
|
||
window.pointEntities.forEach((entity) => {
|
||
viewer.entities.remove(entity);
|
||
});
|
||
window.pointEntities = [];
|
||
this.cancelEvent();
|
||
window.entitiy && viewer.entities.remove(window.entitiy);
|
||
window.entitiy = null;
|
||
viewer.trackedEntity = null;
|
||
document.getElementsByTagName("body").item(0).style.cursor = "default";
|
||
}
|
||
|
||
// 关闭双击事件
|
||
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
|
||
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
|
||
);
|
||
},
|
||
registerEvent() {
|
||
this.addMouseListener();
|
||
this.addMouseClick(); // 地图鼠标左键单击事件
|
||
this.addMouseRightClick();
|
||
this.addClockEvent();
|
||
},
|
||
cancelEvent() {
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); //移除事件
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); //移入事件
|
||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK); //右击事件
|
||
},
|
||
addClockEvent() {
|
||
// let handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
||
// handler.setInputAction((movement) => {
|
||
// let pick = scene.pick(movent.position);
|
||
// // if(){
|
||
|
||
// // }
|
||
// }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
//监听时间变化
|
||
viewer.clock.onTick.addEventListener((e) => {
|
||
if (viewer.clock.shouldAnimate === true) {
|
||
let ori = this.orientation.getValue(viewer.clock.currentTime); //获取偏向角
|
||
let center = this.position.getValue(viewer.clock.currentTime); //获取位置
|
||
let transform = Cesium.Matrix4.fromRotationTranslation(
|
||
Cesium.Matrix3.fromQuaternion(ori),
|
||
center
|
||
); //将偏向角转为3*3矩阵,利用实时点位转为4*4矩阵
|
||
viewer.camera.lookAtTransform(
|
||
transform,
|
||
new Cesium.Cartesian3(-1, 0, 0)
|
||
); //将相机向后面放一点
|
||
// viewer.camera.lookAtTransform(transform);
|
||
}
|
||
});
|
||
},
|
||
// 鼠标左侧单击事件
|
||
addMouseClick() {
|
||
let that = this;
|
||
that.handler.setInputAction(function (movement) {
|
||
console.log("========单击事件========");
|
||
// 添加区域情况
|
||
if (that.isAddStatus) {
|
||
// 平面坐标(x,y)
|
||
let windowPosition = movement.position;
|
||
// 三维坐标(x,y,z)
|
||
let ellipsoid = viewer.scene.globe.ellipsoid;
|
||
let cartesian = viewer.camera.pickEllipsoid(
|
||
windowPosition,
|
||
viewer.scene.globe.ellipsoid
|
||
);
|
||
// 坐标转换:世界坐标转换为经纬度
|
||
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
|
||
let lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度
|
||
let lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
|
||
// 经度在前纬度在后
|
||
// that.pointPositionList.push([Number(lng.toFixed(6)),Number(lat.toFixed(6)),30]);
|
||
that.pointPositionList.push([
|
||
cartesian.x,
|
||
cartesian.y,
|
||
cartesian.z + 20,
|
||
]);
|
||
if (!cartesian) {
|
||
return;
|
||
}
|
||
// 实例化点实体
|
||
let point = viewer.entities.add({
|
||
name: "gon_point",
|
||
position: new Cesium.Cartesian3(
|
||
cartesian.x,
|
||
cartesian.y,
|
||
cartesian.z + 20
|
||
),
|
||
point: {
|
||
color: Cesium.Color.WHITE,
|
||
pixelSize: 10,
|
||
outlineColor: Cesium.Color.BLACK,
|
||
outlineWidth: 1,
|
||
},
|
||
});
|
||
window.pointEntities.push(point);
|
||
|
||
if (window.pointEntities.length > 1) {
|
||
that.initTimeline();
|
||
that.readyPath();
|
||
that.createModel();
|
||
}
|
||
// 存储点的实体,用于下图
|
||
}
|
||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||
},
|
||
// 鼠标移入事件,添加状态改变鼠标光标
|
||
addMouseListener() {
|
||
let that = this;
|
||
// const handler = new Cesium.ScreenSpaceEventHandler(
|
||
// viewer.scene.canvas
|
||
// );
|
||
that.handler.setInputAction(function (movement) {
|
||
console.log("========移入事件========");
|
||
if (that.isAddStatus) {
|
||
document.getElementsByTagName("body").item(0).style.cursor =
|
||
"pointer";
|
||
} else {
|
||
document.getElementsByTagName("body").item(0).style.cursor =
|
||
"default";
|
||
}
|
||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||
},
|
||
// 鼠标右击事件,添加状态改变鼠标光标
|
||
addMouseRightClick() {
|
||
let that = this;
|
||
that.handler.setInputAction(function (movement) {
|
||
console.log("========右击事件========");
|
||
// 结束区域查询
|
||
that.isAddStatus = false;
|
||
that.cancelEvent();
|
||
document.getElementsByTagName("body").item(0).style.cursor = "default";
|
||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang='stylus' scoped>
|
||
#path-viewer {
|
||
height: 80vh;
|
||
width: 100%;
|
||
}
|
||
|
||
.path-container {
|
||
position: absolute;
|
||
top: 70px;
|
||
left: 70px;
|
||
}
|
||
|
||
.path-container .box-card {
|
||
width: 250px;
|
||
}
|
||
|
||
.fly-box {
|
||
padding-top: 44px;
|
||
padding-bottom: 10px;
|
||
width: 300px;
|
||
z-index: 900;
|
||
// right: 10px;
|
||
// left: 59px;
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
z-index: 999 !important;
|
||
z-index: 100;
|
||
border-bottom: 1px solid #008aff70;
|
||
border-left: 1px solid #008aff70;
|
||
border-right: 1px solid #008aff70;
|
||
box-shadow: 0 4px 15px 1px #02213bb3;
|
||
border-radius: 0;
|
||
background: linear-gradient(to left, #ffffff, #ffffff) left bottom no-repeat, linear-gradient(to bottom, #ffffff, #ffffff) left bottom no-repeat, linear-gradient(to left, #ffffff, #ffffff) right bottom no-repeat, linear-gradient(to left, #ffffff, #ffffff) right bottom no-repeat;
|
||
background-size: 1px 10px, 10px 1px, 1px 10px, 10px 1px;
|
||
background-color: rgba(22, 51, 76, 0.8) !important;
|
||
}
|
||
|
||
.fly-title {
|
||
height: 44px;
|
||
width: 100%;
|
||
line-height: 44px;
|
||
overflow: hidden;
|
||
height: 41px;
|
||
line-height: 41px;
|
||
background: url('http://mars3d.cn/project/vue/assets/msg-title-bg.53c38de6.png'); // mars3d.cn/project/vue/assets/msg-title-bg.53c38de6.png);
|
||
background-size: 10px 44px;
|
||
padding: 0 5px 0 10px;
|
||
color: #fff;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
box-sizing: border-box;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.fly-title i {
|
||
float: right;
|
||
margin-right: 10px;
|
||
cursor: pointer;
|
||
line-height: 40px;
|
||
}
|
||
|
||
.fly-content {
|
||
height: 100%;
|
||
overflow: auto;
|
||
padding: 5px 15px;
|
||
}
|
||
|
||
.fly-operation {
|
||
text-align: center;
|
||
margin-bottom: 10px;
|
||
padding-top: 10px;
|
||
}
|
||
|
||
.fly-operation button {
|
||
height: 32px;
|
||
background: rgba(0, 138, 255, 0.5);
|
||
border: none;
|
||
padding-left: 10px;
|
||
padding-right: 10px;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.fly-operation button i {
|
||
padding: 0 5px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.fly-table {
|
||
clear: both;
|
||
max-width: 100%;
|
||
box-sizing: border-box;
|
||
position: relative;
|
||
transition: opacity 0.3s;
|
||
color: #cdcdcd;
|
||
font-size: 12px;
|
||
border: solid 1px;
|
||
border-color: #0b67b7;
|
||
border-top-color: #c1c1d5;
|
||
min-height: 180px;
|
||
}
|
||
|
||
.fly-table table {
|
||
width: 100%;
|
||
border-spacing: 0;
|
||
border-collapse: separate;
|
||
}
|
||
|
||
.fly-table table td, fly-table table th {
|
||
padding: 10px;
|
||
}
|
||
|
||
.fly-table-header {
|
||
background: rgba(0, 138, 255, 0.2);
|
||
/* text-align: left; */
|
||
height: 32px;
|
||
}
|
||
|
||
.fly-table-body {
|
||
background: rgba(22, 51, 76, 0.5);
|
||
color: white;
|
||
}
|
||
|
||
.fly-table-body input {
|
||
color: white;
|
||
background: transparent;
|
||
border: none;
|
||
}
|
||
|
||
.fly-table-operation {
|
||
text-align: center;
|
||
}
|
||
|
||
.fly-table-operation i {
|
||
padding: 0 2px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.fly-tab-coord {
|
||
color: white;
|
||
padding: 5px;
|
||
}
|
||
|
||
.fly-tab-coord .title-box {
|
||
font-size: 15px;
|
||
padding: 5px;
|
||
}
|
||
|
||
.fly-tab-coord .path-coord {
|
||
padding: 5px;
|
||
border: solid 1px #295f8f;
|
||
}
|
||
|
||
.fly-tab-coord .fly-coord-content {
|
||
max-height: 520px;
|
||
overflow: auto;
|
||
}
|
||
|
||
.fly-tab-coord .path-coord input {
|
||
color: white;
|
||
background: transparent;
|
||
width: 100px;
|
||
}
|
||
|
||
.fly-tab-coord .coord-btn {
|
||
text-align: center;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.fly-tab-coord .coord-btn button {
|
||
padding: 3px 10px;
|
||
font-size: 12px;
|
||
margin: 0 10px;
|
||
color: white;
|
||
background: rgba(120, 255, 53, 0.3);
|
||
border: none;
|
||
}
|
||
|
||
.handle {
|
||
box-sizing: border-box;
|
||
position: absolute;
|
||
z-index: 1;
|
||
width: 10px;
|
||
height: 10px;
|
||
opacity: 0;
|
||
}
|
||
|
||
.handle-l {
|
||
height: auto;
|
||
top: 10px;
|
||
left: 0;
|
||
bottom: 10px;
|
||
}
|
||
|
||
.handle-r {
|
||
height: auto;
|
||
top: 10px;
|
||
right: 0;
|
||
bottom: 10px;
|
||
}
|
||
/deep/.cesium-viewer-timelineContainer{
|
||
display: none !important;
|
||
}
|
||
.handle-t {
|
||
width: auto;
|
||
top: 0;
|
||
left: 10px;
|
||
right: 10px;
|
||
}
|
||
|
||
.handle-b {
|
||
width: auto;
|
||
bottom: 0;
|
||
left: 10px;
|
||
right: 10px;
|
||
}
|
||
|
||
.handle-lb {
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.handle-rb {
|
||
bottom: 0;
|
||
right: 0;
|
||
}
|
||
</style> |