537 lines
14 KiB
Vue
Raw Normal View History

2023-11-13 16:54:28 +08:00
<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,
2023-11-16 18:37:50 +08:00
positions: pointsArr,
2023-11-13 16:54:28 +08:00
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: {
2023-11-18 15:51:49 +08:00
image: "@/assets/images/Mars3DImg/particle/smoke.png",
2023-11-13 16:54:28 +08:00
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,
2023-11-18 15:51:49 +08:00
image: "@/assets/images/Mars3DImg/textures/line-color-yellow.png",
2023-11-13 16:54:28 +08:00
speed: 20
});
map.flyToGraphic(graphic);
lastRoute = graphic;
};
// html格式处理
const htmlDeal = (row: any) => {
console.log(row);
let passArr = [...new Set(row.road)];
2023-11-16 18:37:50 +08:00
let html = `全场${mars3d.MeasureUtil.formatDistance(row.allDistance)},途径:${passArr.join(",")}`;
2023-11-13 16:54:28 +08:00
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: {
2023-11-18 15:51:49 +08:00
image: "@/assets/images/Mars3DImg/marker/route-start.png",
2023-11-13 16:54:28 +08:00
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: {
2023-11-18 15:51:49 +08:00
image: "@/assets/images/Mars3DImg/marker/route-end.png",
2023-11-13 16:54:28 +08:00
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%;
}
}
}
}
2023-11-16 18:37:50 +08:00
// 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;
}
}
2023-11-13 16:54:28 +08:00
</style>