天地图可拖拽驾车路线规划

摘要:有巡检业务或规划路线的场景,这个功能还是比较实用的;目前高德有类似的功能,天地图目前还没有;手动封装一个,效果还行;

效果图

在这里插入图片描述

天地图驾车规划接口

在这里插入图片描述

封装方法
// 开始marker图片_换成自己
import startPng from '@/assets/image/map/start.png';
// 结束marker图片_换成自己
import endPng from '@/assets/image/map/end.png';
// 途经点marker图片_换成自己
import midPng from '@/assets/image/map/mid.png';
// 弹窗提示_换成自己
import {AzMessages} from '@/views/Utils/index';
import { v4 as uuidv4 } from 'uuid';
const T = (window as any).T;
class DragRoute {
    map: any;
    startLngLat: any;
    endLngLat: any;
    midList: any;
    line: any;
    curInfoWindow: any;
    startEndMarker: any;
    eventListenerMap: any;
    constructor(map: any, line: any) {
        // 天地图
        this.map = map;
        // 开始坐标
        this.startLngLat = {};
        // 结束坐标
        this.endLngLat = {};
        // 线
        this.line = line;
        // 途径点
        this.midList = [];

        const curLngLats = this.line.getLngLats();
        this.startLngLat = curLngLats[0];
        this.endLngLat = curLngLats[curLngLats.length - 1];
        // 当前信息窗口
        this.curInfoWindow = new T.InfoWindow();
        // 开始结束标记点_后续销毁用
        this.startEndMarker = [];
        // 事件监听Map_后续销毁用
        this.eventListenerMap = new Map();
        this.init();
    }
    init() {
        this.createStartMarker();
        this.createEndMarker();
        this.createLine();
    }
    // 创建开始
    createStartMarker() {
        if (!this.map) { return; }
        var marker = new T.Marker(this.startLngLat, {
            icon:  new T.Icon({
                iconUrl: startPng,
                iconSize: new T.Point(25, 30),
                iconAnchor: new T.Point(14, 30)
            }),
            draggable: true,
        });
        marker.uuid = uuidv4();
        this.map.addOverLay(marker);

        const dragendCallback = () => {
            this.startLngLat = marker.getLngLat();
            this.change();
        }
        marker.addEventListener('dragend', dragendCallback);
        this.startEndMarker.push(marker);
        // 把事件存起来_后续销毁用
        this.eventListenerMap.set(marker.uuid, {
            marker, event:'dragend', eventListener: dragendCallback
        });
    }
    // 创建结束
    createEndMarker() {
        if (!this.map) { return; }
        var marker = new T.Marker(this.endLngLat, {
            icon:  new T.Icon({
                iconUrl: endPng,
                iconSize: new T.Point(25, 30),
                iconAnchor: new T.Point(14, 30)
            }),
            draggable: true,
        });
        marker.uuid = uuidv4();
        this.map.addOverLay(marker);

        const dragendCallback = () => {
            this.endLngLat = marker.getLngLat();
            this.change();
        }
        marker.addEventListener('dragend', dragendCallback);
        this.startEndMarker.push(marker);
        // 把事件存起来_后续销毁用
        this.eventListenerMap.set(marker.uuid, {
            marker, event:'dragend', eventListener: dragendCallback
        });
    }
    createLine() {
        if (!this.map) { return; }
        this.line.setLngLats([this.startLngLat, this.endLngLat]);
        const mouseupCallback = (e: any) => {
            this.createMidMarker(e.lnglat);
        }
        this.line.addEventListener('mouseup', mouseupCallback);
        // 把事件存起来_后续销毁用
        this.eventListenerMap.set('line', {
            marker: this.line, event:'mouseup', eventListener: mouseupCallback 
        })
    }
    // 创建途径点
    createMidMarker(lngLat: any) {
        if (!this.map) { return; }
        if (this.midList > 19) {
            AzMessages('warning', '最多可添加20个途径点');
            return;
        }
        var marker = new T.Marker(lngLat, {
            icon:  new T.Icon({
                iconUrl: midPng,
                iconSize: new T.Point(25, 30),
                iconAnchor: new T.Point(14, 30)
            }),
            draggable: true,
        });
        marker.uuid = uuidv4();
        this.map.addOverLay(marker);
        this.midList.push(marker);

        const dragendCallback = () => {
            this.change();
            this.openInfoWindow(marker);
        }
        const mousedownCallback = () => {
            this.openInfoWindow(marker);
        }
        const dragstartCallback = () => {
            marker.closeInfoWindow();
        }
        marker.addEventListener('dragend', dragendCallback);
        marker.addEventListener('mousedown',mousedownCallback);
        marker.addEventListener('dragstart', dragstartCallback);
        // 把事件存起来_后续销毁用
        this.eventListenerMap.set(`${marker.uuid}Dragend`, {
            marker, event:'dragend', eventListener: dragendCallback
        });
        this.eventListenerMap.set(`${marker.uuid}mousedown`, {
            marker, event:'mousedown', eventListener: mousedownCallback
        });
        this.eventListenerMap.set(`${marker.uuid}dragstart`, {
            marker, event:'dragstart', eventListener: dragstartCallback
        });
    }
    change() {
        // 有点改变了
        const orig = `${this.startLngLat.lng},${this.startLngLat.lat}`;
        const dest = `${this.endLngLat.lng},${this.endLngLat.lat}`;
        let mid = [];
        for (let i = 0; i < this.midList.length; i++) {
            const item = this.midList[i].getLngLat();
            mid.push(`${item.lng},${item.lat}`);
        }
        this.fetchLngLat({
            orig,
            dest,
            mid: mid.join(';')
        });
    }
    fetchLngLat(params: {orig: string, dest: string, mid: string}) {
        return new Promise((resolve, reject) => {
            const {orig, dest, mid} = params;
            // 注意换成你的天地图密钥
            const tk = '您的密钥';
            const url = `https://api.tianditu.gov.cn/drive?postStr={"orig":"${orig}","dest":"${dest}","mid": "${mid}","style":"1"}&type=search&tk=${tk}`;
            fetch(url)
            .then(response => {
                if (!response.ok || response.status !== 200) {
                    throw new Error(response.statusText);
                }
                return response.text(); // 获取响应的文本内容
            })
            .then(text => {
                const parser = new DOMParser();
                const xmlDoc = parser.parseFromString(text, "application/xml"); // 解析XML文本
                // 查找<routelatlon>标签
                const routeLatLonElement: any = xmlDoc.getElementsByTagName('routelatlon')[0];
                if (routeLatLonElement) {
                    // 获取<routelatlon>标签下的文本,即经纬度数据
                    const latLonData = routeLatLonElement.textContent.trim();
                    const latLonArray = latLonData.split(';').map((item: string) => item.trim()).filter((item: any) => {
                        return item || false;
                    }); // 分割字符串并去除空白
                    this.updateLine(latLonArray); 
                    resolve(latLonArray);
                } else {
                    resolve([orig, dest]);
                }
            })
            .catch(error => {
                reject(error);
            });
        });
    }
    updateLine(lngLats: any) {
        if (!this.map) { return; }
        const points = lngLats.map((item: any) => {
            const [lng, lat] = item.split(',');
            return new T.LngLat(lng, lat);
        });
        this.line.setLngLats(points);
    }
    openInfoWindow(curMarker: any) {
        if (!this.map) { return; }
        const lngLat = curMarker.getLngLat();

        const parentDiv = document.createElement('div');



        const childDel = document.createElement('button');
        childDel.innerText = '删除';

        // parentDiv.appendChild(childUpper);
        // parentDiv.appendChild(childDown);
        parentDiv.appendChild(childDel);

        this.curInfoWindow.setContent(parentDiv);

        const delClickCallback = () => {
            curMarker.closeInfoWindow()
            this.map.removeOverLay(curMarker);
            this.midList = this.midList.filter((item: any) => {
                return item.uuid !== curMarker.uuid;
            });
            this.change();
        }
        childDel.addEventListener('click', delClickCallback);
        // 把事件存起来_后续销毁用
        this.eventListenerMap.set(`${curMarker.uuid}delClick`, {
            marker: childDel, event:'click', eventListener: delClickCallback
        });
        curMarker.openInfoWindow(this.curInfoWindow, lngLat);
    }
    handleMidListSort(action: string, uuid: string) {
        if (action === 'upper') {
            const index = this.midList.findIndex((item: any) => item.uuid === uuid);
            if (index > 0) { // 如果不是第一个元素
                [this.midList[index], this.midList[index - 1]] = [this.midList[index - 1], this.midList[index]];
                this.change();
            }

        } else if (action === 'down') {
            const index = this.midList.findIndex((item: any) => item.uuid === uuid);
            if (index < this.midList.length - 1) { // 如果不是最后一个元素
                // 交换当前元素和后一个元素的位置
                [this.midList[index], this.midList[index + 1]] = [this.midList[index + 1], this.midList[index]];
                this.change();
            }
        }
    }
    end() {
        if (!this.map) { return; }
        for (let i = 0; i< this.startEndMarker.length; i++) {
            this.map.removeOverLay(this.startEndMarker[i]); 
        }
        for (let i = 0; i< this.midList.length; i++) {
            this.map.removeOverLay(this.midList[i]);
            this.midList[i].closeInfoWindow();
        }
        this.reset();
    }
    reset() {
        this.map = null;
        this.line = null;
        this.midList = [];
        this.curInfoWindow = null;
        this.startEndMarker = [];
        for (const [key, value] of this.eventListenerMap) {
            value.marker.removeEventListener(value.event, value.eventListener);
        }
        this.eventListenerMap.clear();
    }
}
export default DragRoute;
使用

注意:因为传入的是你创建的line; 引用内存地址是一样的;所以以你想获取最新的坐标直接掉api就可以;
line.getLngLats();

// 这里用的是React; 你可以换成你喜欢的vue
const dragRouteEditRef = useRef();
// 开始
const handleStartDragRouteEdit = () => {
	// 传入你的地图和线
	dragRouteEditRef.current = new DragRoute(map, line);
}
// 结束
const handleEndDragRouteEdit = () => {
	dragRouteEditRef.current.end();
	dragRouteEditRef.current = null;
};
map和line创建
//初始化地图对象
map = new T.Map("mapDiv");
//设置显示地图的中心点和级别
map.centerAndZoom(new T.LngLat(116.40969, 39.94940), zoom);
points = [];
points.push(new T.LngLat(116.41136, 39.97569));
points.push(new T.LngLat(116.411794, 39.9068));
points.push(new T.LngLat(116.32969, 39.92940));
points.push(new T.LngLat(116.385438, 39.90610));
//创建线对象
var line = new T.Polyline(points);
//向地图上添加线
map.addOverLay(line);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值