Mopbox 根据绘制矩形区域,下载该区域详细地图

101 阅读1分钟

主要思路:

  1. 根据坐标 获取 mapbox 瓦片范围
  2. 每张瓦片 256 像素计算出 地图容器的 宽和高
  3. 新建 mapbox 实例 等待地图加载完
  4. 调用getCanvas 获取 base64 并下载
    const renderLoading = () => {
        const loadingContainer = document.createElement('div');
        loadingContainer.classList.add(styles['download-loading'])
        document.body.appendChild(loadingContainer);
        loadingContainer.style = {
            position: 'absolute',
            top: '0',
            left: '0',
            right: '0',
            bottom: "0"
        }

        ReactDOM.render(<Loading style={{ display: 'block' }} />, loadingContainer);
    }

    const removeLoading = () => {
        const loadingContainer = document.getElementsByClassName(styles['download-loading']);
        document.body.removeChild(loadingContainer[0]);
    }
    const latLonToTile = (lat, lon, zoom) => {
        const n = Math.pow(2, zoom);
        const xTile = Math.floor((lon + 180) / 360 * n);
        const yTile = Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * n);
        return { x: xTile, y: yTile };
    };

    const downloadImage = (dataUrl, filename) => {
        const link = document.createElement('a');
        link.href = dataUrl;
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        removeLoading()
    };
    
    
     const handleDownloadMap = async (feature) => {
        Message.info("正在下载地图, 请您耐心等待 2~3 分钟!")
        const zoom = 18;
        const tileSize = 256;

        try {

            renderLoading()
            const coordinates = feature.geometry.coordinates[0];
            const swLng = Math.min(...coordinates.map(pt => pt[0]));
            const swLat = Math.min(...coordinates.map(pt => pt[1]));
            const neLng = Math.max(...coordinates.map(pt => pt[0]));
            const neLat = Math.max(...coordinates.map(pt => pt[1]));
            // 计算中心点的经度
            const centerLng = (swLng + neLng) / 2;
            // 计算中心点的纬度
            const centerLat = (swLat + neLat) / 2;
            // 计算瓦片坐标范围
            const swTile = latLonToTile(swLat, swLng, zoom);
            const neTile = latLonToTile(neLat, neLng, zoom);

            // 计算瓦片的行列索引
            const startX = swTile.x;
            const startY = swTile.y;
            const endX = neTile.x;
            const endY = neTile.y;


            // 获取瓦片数量
            const tileWidthCount = Math.abs(endX - startX) + 1; // 横向瓦片数量
            const tileHeightCount = Math.abs(endY - startY) + 1; // 纵向瓦片数量

            // 计算宽高(瓦片尺寸为 256x256 像素)
            const width = tileWidthCount * tileSize;
            const height = tileHeightCount * tileSize;

            const NewMap = () => {

                return <Map
                    onStyleLoad={(map) => {
                        // mapRef.current = map;
                        Message.success("地图下载成功")
                        const canvas = map.getCanvas()
                        if (canvas) {
                            setTimeout(() => {
                                const dataUrl = canvas.toDataURL('image/png');
                                downloadImage(dataUrl, 'map.png');
                                const downloadMap = document.getElementsByClassName('download-map');
                                document.body.removeChild(downloadMap[0]);
                            }, 1000);
                        }
                    }}

                    opt={{
                        center: [centerLng, centerLat],
                        zoom: [zoom]
                    }}
                    style={{ width, height }}
                >
                </Map>
            }

            const container = document.createElement('div');
            container.classList.add('download-map')
            container.style.visibility = 'hidden';
            document.body.appendChild(container);
            ReactDOM.render(<NewMap />, container);
            container.style.display = "none"





        } catch (error) {
            const elements = document.getElementsByClassName('download-map');
            Message.error("下载失败,请刷新页面重试!");
            document.body.removeChild(elements[0]);
        }
    };