| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- <template>
- <view style="height:100vh;">
- <view id="map"></view>
- <view class="info-box">
- <text>{{currentStep}}</text>
- </view>
- </view>
- </template>
- <script>
- export default {
- data() {
- return {
- map: null,
- routeLatLngs: [],
- marker: null,
- watchId: null,
- currentStep: "正在规划路线...",
- instructions: [],
- instrIndex: 0,
- start: [39.916527, 116.397128],
- end: [39.904211, 116.407395]
- };
- },
- onReady() {
- this.initMap();
- this.calcRoute();
- this.startGPS();
- },
- methods: {
- /** 1. 初始化地图 */
- initMap() {
- this.map = L.map("map").setView(this.start, 15);
- L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
- maxZoom: 19,
- }).addTo(this.map);
- },
- /** 2. GraphHopper 路线规划 */
- calcRoute() {
- const url =
- `https://graphhopper.com/api/1/route?` +
- `point=${this.start[0]},${this.start[1]}` +
- `&point=${this.end[0]},${this.end[1]}` +
- `&vehicle=car&instructions=true&locale=cn&key=fb959050-3a0c-4c6b-b722-5c322b2085c9`;
- uni.request({
- url,
- success: (res) => {
- const path = res.data.paths[0];
- this.instructions = path.instructions;
- const coords = path.points.coordinates;
- this.routeLatLngs = coords.map(c => [c[1], c[0]]);
- // 绘路线
- L.polyline(this.routeLatLngs, { color: "blue", weight: 5 }).addTo(this.map);
- this.map.fitBounds(this.routeLatLngs);
- // 设置起点终点 Marker
- L.marker(this.start).addTo(this.map).bindPopup("起点");
- L.marker(this.end).addTo(this.map).bindPopup("终点");
- this.currentStep = "路线规划完成,开始导航...";
- }
- });
- },
- /** 3. 开始实时 GPS 监听 */
- startGPS() {
- const _this = this;
- this.watchId = navigator.geolocation.watchPosition(
- (pos) => {
- const lat = pos.coords.latitude;
- const lng = pos.coords.longitude;
- _this.updatePosition(lat, lng);
- _this.checkNextInstruction(lat, lng);
- },
- (err) => { console.log("GPS error:", err); },
- { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }
- );
- },
- /** 4. 更新用户位置 + 地图跟随 */
- updatePosition(lat, lng) {
- if (!this.marker) {
- this.marker = L.marker([lat, lng]).addTo(this.map);
- } else {
- this.marker.setLatLng([lat, lng]);
- }
- // 地图跟随
- this.map.panTo([lat, lng]);
- },
- /** 5. 判断导航步骤 */
- checkNextInstruction(lat, lng) {
- if (!this.instructions.length) return;
- const step = this.instructions[this.instrIndex];
- const [fromIdx, toIdx] = step.interval;
- const stepCoords = this.routeLatLngs[fromIdx];
- const dist = this.getDistance(lat, lng, stepCoords[0], stepCoords[1]);
- if (dist < 20) { // 距离下一个步骤 < 20 米时触发
- this.currentStep = step.text;
- // 进入下一步
- if (this.instrIndex < this.instructions.length - 1) {
- this.instrIndex++;
- }
- }
- },
- /** 工具:两点间距离 */
- getDistance(lat1, lon1, lat2, lon2) {
- const R = 6378137;
- const dLat = (lat2 - lat1) * Math.PI / 180;
- const dLon = (lon2 - lon1) * Math.PI / 180;
- const a =
- Math.sin(dLat/2) * Math.sin(dLat/2) +
- Math.cos(lat1 * Math.PI/180) *
- Math.cos(lat2 * Math.PI/180) *
- Math.sin(dLon/2) * Math.sin(dLon/2);
- return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
- }
- },
- onUnload() {
- if (this.watchId) {
- navigator.geolocation.clearWatch(this.watchId);
- }
- }
- };
- </script>
- <style>
- #map { width: 100%; height: 75vh; }
- .info-box {
- padding: 20rpx;
- font-size: 32rpx;
- }
- </style>
- <!-- Leaflet -->
- <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
- <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css">
|