html
<!-- 路径展示 -->
<div class="lujing-list" :style="{ left: lif }">
<div class="bottomBg"></div>
<div class="head">
<headTitle title="路径展示" style="width: 80%"></headTitle>
<el-button type="primary" @click="lxHide" circle
style="width: 25px; height: 25px; border: 0; align-self: center">
<ArrowLeftBold style="width: 1em; height: 1em" />
</el-button>
</div>
<div class="show-area">
<div class="luxian-title">转移路线:</div>
<div v-for="(item, index) in routesTxtList" :key="index" class="lx-area">
<p>{{ item }}</p>
<p class="pxia" v-if="index != routesTxtList.length -1">↓</p>
</div>
</div>
</div>
data
//以下是轨迹
const trackLayer = ref();
const passCoordinates = ref([]);
// 记录开始动画的时间
const startTime = ref(0);
// 轨迹分割的颗粒度,数值越小分的越细
const particle = 20;
// 轨迹动画的速度,数值越大位移越快
const speed = 5;
let routesTxtList = ref([]) //路径文本列表
let lif = ref('-100%');//左侧面板距离
js
//画路线
function drawLuxian(start, end){
removeTrak()
axios.get('https://api.tianditu.gov.cn/drive?postStr={orig:"' + start + '",dest:"' + end + '",style:"0"}&type=search&tk=46f132f7078fa807641aa8644dc60eb1', {})
.then(res=>{
if (res?.status == 200){
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(res.data, "application/xml");
let routelatlon = xmlDoc.getElementsByTagName("routelatlon")[0].textContent
routelatlon = routelatlon.substring(0, routelatlon.length - 1);
let routes = xmlDoc.getElementsByTagName("routes")[0].getElementsByTagName("item")
routesTxtList.value = []
for (let i = 0; i < routes.length; i++) {
let strguide = routes[i].getElementsByTagName("strguide")[0];
let text = strguide.textContent; // 获取文本内容
routesTxtList.value.push(text)
}
let list = routelatlon.split(";").map(e=>{
return [parseFloat(e.split(",")[0]), parseFloat(e.split(",")[1])]
})
addTrack(list);
lif.value = '20px'
setTimeout(()=>{
startMove()
},2000)
}
})
}
//以下是巡查轨迹的代码
function createLuxianLayer(trackLine) {
const trackFeature = new Feature({
type: "track",
geometry: trackLine,
});
const geoMarker = new Feature({
type: "geoMarker",
geometry: new Point(passCoordinates.value[0]),
});
geoMarker.setId("point");
const startMarker = new Feature({
type: "iconStart",
geometry: new Point(passCoordinates.value[0]),
});
const endMarker = new Feature({
type: "iconEnd",
geometry: new Point(
passCoordinates.value[passCoordinates.value.length - 1]
),
});
const styles = {
track: new Style({ //轨迹样式
stroke: new Stroke({
width: 3,
color: '#54ff9f',
}),
}),
iconEnd: new Style({//终点
image: new Icon({
anchor: [0.5, 1],
scale: 1,
src: LuxianImg("endMark"),
}),
}),
iconStart: new Style({//起点
image: new Icon({
anchor: [0.5, 1],
src: LuxianImg("start"),
scale: 1, //设置大小
}),
}),
geoMarker: new Style({ //车标
image: new Icon({
src: LuxianImg("trackCar"),
scale: 1,
size: [32, 32],
anchor: [0.5, 1],
offsetY: "32",
}),
}),
};
trackLayer.value = new VectorLayer({
source: new VectorSource({
features: [trackFeature, geoMarker, startMarker, endMarker],
}),
style: (feature) => {
return styles[feature.get("type")];
},
zIndex: 30,
});
map.value.addLayer(trackLayer.value);
}
function move(evt) {
const frameState = evt.frameState;
// 执行动画已经过了多少时间(秒)
const timeout = (frameState.time - startTime.value) / 1000;
let count = Math.round(speed * timeout);
if (count >= passCoordinates.value.length - 1) {
// 确保到达最后一个点位,并停止移动动画
count = passCoordinates.value.length - 1;
stopMove();
}
const point = trackLayer.value.getSource().getFeatureById("point");
point.getGeometry().setCoordinates(passCoordinates.value[count]);
map.value.render();
}
function startMove() {
startTime.value = new Date().getTime();
map.value.on("postrender", move);
// 第一次需要手动调用一遍,否则不执行postcompose
map.value.render();
}
function stopMove() {
map.value.un("postrender", move);
startMove()
}
function addTrack(coordinates) {
const trackLine = new LineString(coordinates);
// 轨迹在投影平面上的长度
const trackLineLen = trackLine.getLength();
// 使用轨迹线计算边界矩形
var bounds = trackLine.getExtent();
// 使用`fitBounds`方法应用边界
map.value.getView().fit(bounds);
// 当前平面的分辨率
const resolution = map.value.getView().getResolution();
// 点有可能是小数,要到终点需要手动添加最后一个点
const pointCount = trackLineLen / (resolution * particle);
for (let i = 0; i <= pointCount; i++) {
passCoordinates.value.push(trackLine.getCoordinateAt(i / pointCount));
}
passCoordinates.value.push(coordinates[coordinates.length - 1]);
map.value.setView(new View({
center: [(parseFloat(coordinates[0][0]) + 0.03), parseFloat(coordinates[0][1])],
projection: 'EPSG:4326',
zoom: 14,
}))
createLuxianLayer(trackLine);
}
function removeTrak() {
if (trackLayer.value && map.value) {
map.value.removeLayer(trackLayer.value);
passCoordinates.value = [];
trackLayer.value = null;
}
}
//车辆图标
function LuxianImg(name) {
return new URL(`../../../assets/imgs/${name}.png`, import.meta.url).href;
}
//路线关闭
function lxHide(){
lif.value = '-100%'
removeTrak()
}
css
.lujing-list{
position: absolute;
top: 330px;
transform: translateY(-50%);
display: flex;
flex-direction: column;
background: linear-gradient(180deg, rgba(28, 46, 105, 0.8) 0%, rgba(66, 97, 194, 0.8) 100%);
backdrop-filter: blur(2px);
border-radius: 5px;
transition: left .8s;
height: 450px;
width: 315px;
padding: 25px 15px;
.bottomBg {
background: url("@/assets/images/oneImage/wenluLeft.png") no-repeat center center;
background-size: cover;
position: absolute;
width: 100%;
height: 398px;
bottom: 0;
left: 0;
}
.head {
display: flex;
height: 30px;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
margin-bottom: 10px;
.el-button--primary {
background-color: #398AC2;
}
}
.show-area{
width: 100%;
height: calc(100% - 40px);
overflow: auto;
position: relative;
z-index: 1;
color: #fff;
.luxian-title{
font-size: 18px;
font-weight: bold;
}
.lx-area{
p{
margin: 0;
}
.pxia{
text-align: center;
font-size: 20px;
}
}
}
}