概述
本文在mapboxGL框架下,分享一种基于高德Web API实现沿路画面的实现。
实现效果
实现
1. 实现思路
- 通过点击获取路径的起点和终点;
- 将多次规划路径的结果连成一条线;
- 当鼠标点击回到第一个点的时候结束绘制;
- 绘制结束后将路径闭合,形成多边形,并对形成的多边形进行处理;
实现代码
vue
<template>
<div class="map">
<lzugismap-map
:onLoad="mapLoaded"
:maxPitch="0"
:minPitch="0"
:pitch="0"
:style="style"
:center="[113.91505797606129, 22.536719264512044]"
:zoom="zoom"
:interactive="true"
>
</lzugismap-map>
<div class="map-tools">
<button :disabled="isDraw" @click="startDraw">绘制</button>
</div>
</div>
</template>
<script>
import { LzugismapMap } from "@lzugismap/vue-lzugismap";
import * as turf from "@turf/turf";
class Geojson {
constructor(features = []) {
this.features = features;
this.type = "FeatureCollection";
}
}
let points = [],
routes = [];
export default {
components: {
LzugismapMap,
},
data() {
return {
map: null,
zoom: 16,
isDraw: false,
};
},
methods: {
mapLoaded(map) {
this.map = map;
map.addSource("route-source", {
type: "geojson",
data: new Geojson(),
});
map.addSource("fill-source", {
type: "geojson",
data: new Geojson(),
});
map.addSource("point-source", {
type: "geojson",
data: new Geojson(),
});
map.addLayer({
id: "route-source-fill",
source: "fill-source",
type: "fill",
paint: {
"fill-color": "red",
"fill-opacity": 0.15,
},
});
map.addLayer({
id: "route-source-line",
source: "route-source",
type: "line",
paint: {
"line-color": "red",
"line-width": 3.5,
},
});
map.addLayer({
id: "route-point",
source: "point-source",
type: "circle",
paint: {
"circle-color": "blue",
"circle-opacity": 0.8,
"circle-radius": 5,
},
});
// this.showRoute();
},
startDraw() {
this.isDraw = true;
points = [];
routes = [];
const that = this;
that.map.getSource("point-source").setData(new Geojson());
that.map.getSource("route-source").setData(new Geojson());
that.map.getSource("fill-source").setData(new Geojson());
that.map.getCanvas().style.cursor = "crosshair";
const mapClickEvt = (e) => {
const point = e.lngLat.toArray();
points.push(point);
that.map
.getSource("point-source")
.setData(new Geojson(points.map((p) => turf.point(p))));
if (points.length > 1) {
const p0 = points[0];
const start = points[points.length - 2];
let end = points[points.length - 1];
const dis = turf.distance(turf.point(p0), turf.point(end)) * 1000;
const isEnd = dis < 10;
if (isEnd) {
end = p0;
}
// driving walking
const url = `https://restapi.amap.com/v3/direction/walking?origin=${start.join(
","
)}&destination=${end.join(
","
)}&output=JSON&key={你申请的key}`;
fetch(url)
.then((res) => res.json())
.then((res) => {
const paths = res?.route?.paths || [];
paths.forEach(({ steps }) => {
steps.forEach(({ polyline }) => {
const _points = polyline
.split(";")
.map((item) => item.split(",").map(Number));
routes = [...routes, ..._points];
});
});
if (isEnd) {
const polygon = turf.lineToPolygon(turf.lineString(routes));
const geojson = turf.polygonSmooth(polygon, { iterations: 10 });
that.map.getSource("route-source").setData(geojson);
that.map.getSource("fill-source").setData(geojson);
that.isDraw = false;
this.map.off("click", mapClickEvt);
that.map.getCanvas().style.cursor = "";
} else {
const line = turf.lineString(routes);
that.map.getSource("route-source").setData(line);
}
});
}
};
this.map.on("click", mapClickEvt);
},
},
};
</script>
<style scoped lang="scss">
.map {
width: 100%;
height: 100%;
}
.map-tools {
position: absolute;
right: 2rem;
top: 2rem;
z-index: 99;
}
</style>