2023-11-18 15:51:49 +08:00

537 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="main-content">
<div class="main-content-title">
<span>路线导航</span>
<el-icon size="16" color="#fff" @click="closeDiv"><Close /></el-icon>
</div>
<div class="item-classify">
<div class="item-classify-item">
<span>起点</span>
<el-input :value="mapPosition.startPosition" disabled />
<el-button type="primary" @click="startPicking">图上选点</el-button>
</div>
<div class="item-classify-item">
<span>终点</span>
<el-input :value="mapPosition.endPosition" disabled />
<el-button type="primary" @click="endPicking">图上选点</el-button>
</div>
</div>
<div class="table-list" v-if="tableData.length > 0">
<div class="table-head">
<div class="tr">
<div class="td"><span>序号</span></div>
<div class="td">推荐线路</div>
</div>
</div>
<div class="table-body">
<div class="tr" v-for="(item, index) in tableData" :key="index">
<div class="td">方案{{ index + 1 }}</div>
<div class="td">
<div>
<el-button type="primary" @click="highLightRoute(item)" size="small">高亮路线</el-button>
<el-button type="primary" @click="startFly(item, index)" size="small">开始漫游</el-button>
</div>
<div>{{ htmlDeal(item) }}</div>
</div>
</div>
</div>
</div>
<div class="speed-set" v-if="tableData.length > 0">
<span>速度</span>
<el-input-number v-model="mapPosition.speed" controls-position="right" />
<span>km/h</span>
</div>
</div>
</template>
<script lang="ts" setup>
//引入cesium基础库
import "mars3d-cesium/Build/Cesium/Widgets/widgets.css";
import * as Cesium from "mars3d-cesium";
//导入mars3d主库
import "mars3d/dist/mars3d.css";
import * as mars3d from "mars3d";
import { ref, watch, onMounted, onUnmounted, reactive, computed } from "vue";
import type { UnwrapRef } from "vue";
import { ElMessage } from "element-plus";
import { GlobalStore } from "@/stores";
const props = defineProps(["mapInstance"]);
const emits = defineEmits(["hiddenConfim"]);
const mapPosition = ref({
startPosition: "",
endPosition: "",
speed: 200
});
const globalStore = GlobalStore();
const tableData = ref<any>([]);
let map: any = props.mapInstance;
let routeLayer: any;
let gaodeRoute: any; // 高德路径规划
let startGraphic: any, endGraphic: any;
onMounted(() => {
routeLayer = new mars3d.layer.GraphicLayer();
map.addLayer(routeLayer);
gaodeRoute = new mars3d.query.GaodeRoute({
key: ["ad31e514e7e740179d6d8f182720bcf5"]
});
});
// 模型路线漫游
const startFly = (row: any, index: number) => {
// 加载完成在加载小车,否则地形未加载完成,小车会处于地下
productRoute(row, index);
};
// 生成路线
const productRoute = (obj: any, index: number) => {
console.log(obj);
console.log(startGraphic);
console.log(endGraphic);
const graphic = routeLayer.getGraphicById(obj.id);
console.log(graphic);
let pointsArr = [] as any;
obj.points.map((item: any) => {
pointsArr.push(mars3d.LngLatPoint.fromArray(item));
});
console.log(pointsArr);
const newRoutePath = new mars3d.graphic.FixedRoute({
id: obj.id + "-" + index,
name: "路线-" + index,
speed: 200,
positions: pointsArr,
clockLoop: false, // 是否循环播放
model: {
url: "//data.mars3d.cn/gltf/mars/jingche/jingche.gltf",
heading: 90,
mergeOrientation: true, // 用于设置模型不是标准的方向时的纠偏处理,在orientation基础的方式值上加上设置是heading值
minimumPixelSize: 50
},
camera: {
type: "gs",
pitch: -30,
radius: 500
},
polyline: {
color: "#ffff00",
width: 3
}
});
console.log(newRoutePath);
console.log(newRoutePath.info);
routeLayer.addGraphic(newRoutePath);
// 绑定popup
bindPopup(newRoutePath);
newRoutePath.autoSurfaceHeight().then(function (e: any) {
// 启动漫游
newRoutePath.flyTo();
newRoutePath.start();
addParticleSystem(newRoutePath.property);
});
};
const bindPopup = (fixedRoute: any) => {
fixedRoute.bindPopup(
`<div style="width: 200px">
<div>总 距 离:<span id="lblAllLen"> </span></div>
<div>总 时 间:<span id="lblAllTime"> </span></div>
<div>开始时间:<span id="lblStartTime"> </span></div>
<div>剩余时间:<span id="lblRemainTime"> </span></div>
<div>剩余距离:<span id="lblRemainLen"> </span></div>
</div>`,
{ closeOnClick: false }
);
// 刷新局部DOM,不影响popup面板的其他控件操作
fixedRoute.on(mars3d.EventType.postRender, function (event: any) {
const container = event.container; // popup对应的DOM
const params = fixedRoute?.info;
console.log(fixedRoute?.info);
if (!params) {
return;
}
const lblAllLen = container.querySelector("#lblAllLen");
if (lblAllLen) {
lblAllLen.innerHTML = mars3d.MeasureUtil.formatDistance(params.distance_all);
}
const lblAllTime = container.querySelector("#lblAllTime");
if (lblAllTime) {
lblAllTime.innerHTML = mars3d.Util.formatTime(params.second_all / map.clock.multiplier);
}
const lblStartTime = container.querySelector("#lblStartTime");
if (lblStartTime) {
lblStartTime.innerHTML = mars3d.Util.formatDate(Cesium.JulianDate.toDate(fixedRoute.startTime), "yyyy-M-d HH:mm:ss");
}
const lblRemainTime = container.querySelector("#lblRemainTime");
if (lblRemainTime) {
lblRemainTime.innerHTML = mars3d.Util.formatTime((params.second_all - params.second) / map.clock.multiplier);
}
const lblRemainLen = container.querySelector("#lblRemainLen");
if (lblRemainLen) {
lblRemainLen.innerHTML = mars3d.MeasureUtil.formatDistance(params.distance_all - params.distance) || "完成";
}
});
};
// 添加尾气粒子效果
function addParticleSystem(property: any) {
const particleSystem = new mars3d.graphic.ParticleSystem({
position: property,
style: {
image: "@/assets/images/Mars3DImg/particle/smoke.png",
particleSize: 12, // 粒子大小(单位:像素)
emissionRate: 20.0, // 发射速率 (单位:次/秒)
pitch: 40, // 俯仰角
maxHeight: 1000, // 超出该高度后不显示粒子效果
startColor: Cesium.Color.GREY.withAlpha(0.7), // 开始颜色
endColor: Cesium.Color.WHITE.withAlpha(0.0), // 结束颜色
startScale: 1.0, // 开始比例单位相对于imageSize大小的倍数
endScale: 5.0, // 结束比例单位相对于imageSize大小的倍数
minimumSpeed: 1.0, // 最小速度(米/秒)
maximumSpeed: 4.0 // 最大速度(米/秒)
},
attr: { remark: "车辆尾气" }
});
routeLayer.addGraphic(particleSystem);
}
let lastRoute: any;
// 高亮路线
const highLightRoute = (row: any) => {
const graphic = routeLayer.getGraphicById(row.id);
if (lastRoute) {
lastRoute.entityGraphic.material = lastRoute.entityGraphic.material_old;
lastRoute.entityGraphic.width = lastRoute.entityGraphic.width_old;
}
// 动画线材质
graphic.entityGraphic.width = 5;
graphic.entityGraphic.material = mars3d.MaterialUtil.createMaterialProperty(mars3d.MaterialType.LineFlow, {
color: Cesium.Color.CHARTREUSE,
image: "@/assets/images/Mars3DImg/textures/line-color-yellow.png",
speed: 20
});
map.flyToGraphic(graphic);
lastRoute = graphic;
};
// html格式处理
const htmlDeal = (row: any) => {
console.log(row);
let passArr = [...new Set(row.road)];
let html = `全场${mars3d.MeasureUtil.formatDistance(row.allDistance)},途径:${passArr.join(",")}`;
return html;
};
// 查询路线规划
const queryRoute = () => {
if (!startGraphic || !endGraphic) {
return;
}
routeLayer.clear();
console.log(startGraphic.coordinate);
console.log(endGraphic.coordinate);
tableData.value = [];
gaodeRoute.queryDriving({
points: [startGraphic.coordinate, endGraphic.coordinate],
strategy: 5,
success: (data: any) => {
console.log(data);
for (let i = 0; i < data.paths.length; i++) {
const firstItem = data.paths[i];
console.log(new Set(firstItem.road));
const points = firstItem.points;
if (!points || points.length < 1) {
continue;
}
const time = mars3d.Util.formatTime(firstItem.allDuration);
const distance = mars3d.MeasureUtil.formatDistance(firstItem.allDistance);
const html = "<div>总距离:" + distance + "<br/>所需时间:" + time + "</div>";
const graphic = new mars3d.graphic.PolylineEntity({
positions: points,
style: {
clampToGround: true,
material: Cesium.Color.fromRandom({
alpha: 0.7
}),
width: 5
},
attr: firstItem,
popup: html
});
routeLayer.addGraphic(graphic);
tableData.value.push({
id: graphic.id,
...data.paths[i]
});
}
// const firstItem = data.paths[0];
// const points = firstItem.points;
// if (!points || points.length < 1) {
// return;
// }
// const time = mars3d.Util.formatTime(firstItem.allDuration);
// const distance = mars3d.MeasureUtil.formatDistance(firstItem.allDistance);
// const html = "<div>总距离:" + distance + "<br/>所需时间:" + time + "</div>";
// const graphic = new mars3d.graphic.PolylineEntity({
// positions: points,
// style: {
// clampToGround: true,
// material: Cesium.Color.AQUA.withAlpha(0.8),
// width: 5
// },
// attr: firstItem,
// popup: html
// });
// routeLayer.addGraphic(graphic);
// const allTime = mars3d.Util.formatTime(firstItem.allDuration);
// const allDistance = mars3d.MeasureUtil.formatDistance(firstItem.allDistance);
// let dhHtml = "";
// for (let i = 0; i < firstItem.steps.length; i++) {
// const item = firstItem.steps[i];
// dhHtml += item.instruction + "";
// }
},
error: function (msg: any) {
ElMessage(msg);
}
});
};
// 图上拾取起点
const startPicking = () => {
if (startGraphic) {
startGraphic.remove();
startGraphic = null;
}
map.graphicLayer
.startDraw({
type: "billboard",
style: {
image: "@/assets/images/Mars3DImg/marker/route-start.png",
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
}
})
.then((graphic: any) => {
startGraphic = graphic;
const point = graphic.point;
point.format();
queryRoute();
mapPosition.value.startPosition = point.lng + "," + point.lat;
return point.lng + "," + point.lat;
});
};
// 图上拾取终点
const endPicking = () => {
if (endGraphic) {
startGraphic.remove();
startGraphic = null;
}
map.graphicLayer
.startDraw({
type: "billboard",
style: {
image: "@/assets/images/Mars3DImg/marker/route-end.png",
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
}
})
.then((graphic: any) => {
endGraphic = graphic;
const point = graphic.point;
point.format();
queryRoute();
mapPosition.value.endPosition = point.lng + "," + point.lat;
return point.lng + "," + point.lat;
});
};
const closeDiv = () => {
emits("hiddenConfim");
};
onUnmounted(() => {
map = null;
});
</script>
<style scoped lang="scss">
@mixin flex {
display: flex;
align-items: center;
}
// 菜单弹框出现动画
@keyframes fadeIn {
0% {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
100% {
opacity: 1;
transform: none;
}
}
.main-content {
position: absolute;
top: 142px;
right: 28px;
padding-bottom: 10px;
background-image: none !important;
border: 1px solid #008aff70;
border-radius: 2px !important;
background-color: rgba(23, 49, 71, 0.8);
width: 350px;
box-shadow: 0 4px 15px 1px #02213bb3;
animation: fadeIn 1s;
&-title {
@include flex;
width: 100%;
height: 40px;
padding: 0 5px 0 10px;
background-image: url("@/assets/images/Mars3DIcon/subClassTitle.png");
background-size: 100% 100%;
background-repeat: no-repeat;
span {
font-size: 16px;
color: #0089fe;
margin-right: auto;
}
:deep() {
.el-icon {
cursor: pointer;
}
}
}
.item-classify {
padding: 10px;
margin: 0 auto;
display: flex;
flex-direction: column;
&-item {
@include flex;
color: white;
margin-bottom: 10px;
> span {
margin-right: 5px;
white-space: nowrap;
}
:deep() {
.el-input {
width: 65%;
margin-right: 5px;
}
.el-checkbox {
height: auto;
}
.el-checkbox__inner,
.el-radio__inner {
background-color: transparent;
}
.el-checkbox__label,
.el-radio__label {
color: white;
}
}
}
}
.table-list {
padding: 0px 10px 10px 10px;
.table-head {
border: 2px solid white;
.tr {
@include flex;
.td {
color: white;
text-align: center;
font-size: 14px;
}
.td:nth-child(1) {
width: 30%;
border-right: 2px solid white;
}
.td:nth-child(2) {
flex: 1;
}
}
}
.table-body {
border: 2px solid white;
border-top: 0;
.tr:not(:last-child) {
border-bottom: 2px solid white;
}
.tr {
display: flex;
.td:nth-child(1) {
@include flex;
justify-content: center;
width: 30%;
border-right: 2px solid white;
color: white;
text-align: center;
font-size: 14px;
}
.td:nth-child(2) {
flex: 1;
display: flex;
flex-direction: column;
> div:nth-child(1) {
border-bottom: 2px solid white;
padding: 5px;
}
> div:nth-child(2) {
color: white;
font-size: 14px;
padding: 5px;
}
}
}
}
}
.speed-set {
margin-top: 10px;
@include flex;
justify-content: center;
span {
color: white;
}
span:first-child {
margin-right: 5px;
}
span:last-child {
margin-left: 5px;
}
:deep() {
.el-input-number {
width: 50%;
}
}
}
}
// element 组件样式
:deep() {
.el-input__wrapper {
background-color: transparent !important;
}
.el-input__inner {
color: white;
}
.el-input-number__increase,
.el-input-number__decrease {
background-color: transparent;
color: white;
}
.el-button {
background: rgba(51, 89, 181, 0.6);
border-radius: 6px;
border: 0;
}
}
</style>