leaflet 叠加天地图经纬度瓦片绘制网格

本文介绍了如何使用Leaflet库在HTML页面上创建交互式地图,加载天地图瓦片,并通过计算和绘制网格,实现地图区域的网格化显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、index.html

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.css" rel="stylesheet">
    <style>
        * {
            padding: 0;
            margin: 0;
        }
 
        html,
        body,
        #map {
            height: 100%;
            width: 100%;
            overflow: hidden;
        }
    </style>
</head>
 
<body>
    <div id="map"></div>
    <script type="module">
        import {bboxToGrid, gridToBbox, getGridDatasOfView} from './util.js'
 
        L.CRS.CustomEPSG4326 = L.extend({}, L.CRS.Earth, {
            code: 'EPSG:4326',
            projection: L.Projection.LonLat,
            transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5),
            scale: function (zoom) {
                return 256 * Math.pow(2, zoom - 1);
            }
        });
 
        const token = '天地图的key';
        let map = L.map('map', {
            crs: L.CRS.CustomEPSG4326
        }).setView([39.92, 116.39], 18);
        let gridLayers = {};  // 格网图层
 
        L.tileLayer(
            'https://t{s}.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=' +
            token, {
                attribution: false,
                subdomains: [0, 1, 2],
            }
        ).addTo(map);
 
        map.on('load', init());
 
        map.on('moveend', () => {
            init();
        });
 
        function init(){
            const zoom = map.getZoom();
            
            const bounds = map.getBounds();
            const southWest = bounds.getSouthWest();
            const northEast = bounds.getNorthEast();
            const [x1,y1,x2,y2] = [southWest.lng, southWest.lat, northEast.lng, northEast.lat];
 
            // 网格行列号范围获取
            const gridBound = bboxToGrid([x1, y1, x2, y2], zoom);
           
            // 视野范围内行列号数据获取
            const gridDatas = getGridDatasOfView(gridBound, zoom);
 
            drawGrids(gridDatas,zoom);
            
        }
 
        // 绘制格网图层
        function drawGrids(gridDatas, zoom){
            removeGridLayers();
            gridDatas.forEach(gridData => {
                const {x, y} = gridData;
                // 网格经纬度范围获取
                const bbox = gridToBbox(x, y, zoom);
                var bounds = [[bbox[1], bbox[0]], [bbox[3], bbox[2]]];
 
                const layer = L.rectangle(bounds, {color: "#ff7800", weight: 1});
 
                const gridName = `${x}_${y}_${zoom}`;
                gridLayers[gridName] = layer;
                map.addLayer(layer);
                // 绘制网格的名称
                addGridNameText(layer.getCenter(), x, y, zoom);
            });
        }
        
         /**
         * 绘制网格的名称
         **/
        function addGridNameText(latlon, x, y, zoom) {
          const text = `${x}x${y}_${zoom}`;
          const myIcon = L.divIcon({
            html: text,
            className: 'my-div-icon',
            iconSize: 30
          });
          const gridNameText = `${text}_txt`;
          const marker = L.marker(latlon, { icon: myIcon });
          gridLayers[gridNameText] = marker;
          map.addLayer(marker);
        }
 
 
        // 删除格网图层
        function removeGridLayers(){
            Object.keys(gridLayers).forEach(key => {
                map.removeLayer(gridLayers[key]);
            });
            gridLayers = {};
        }
 
    </script>
</body>
 
</html>

2、util.js

/**
 * 根据bbox获取瓦片行列号范围
 * @param {*} bbox 
 * @param {*} zoom 
 * @returns 
 */
 export function bboxToGrid(bbox, zoom) {
    const x1 = Math.floor((bbox[0] + 180) / (360 / Math.pow(2, zoom)));
    const y1 = Math.ceil((90 - bbox[1]) / (180 / Math.pow(2, zoom - 1)));
    const x2 = Math.ceil((bbox[2] + 180) / (360 / Math.pow(2, zoom)));
    const y2 = Math.floor((90 - bbox[3]) / (180 / Math.pow(2, zoom - 1)));
    return [x1, y1, x2, y2];
}
 
 
// 视野范围内行列号数据获取
export function getGridDatasOfView(grids) {
    const gridDatas = [];
    for (let i = grids[0]; i < grids[2]; i++) {
        for (let j = grids[3]; j <= grids[1]; j++) {
            const gridData = { x: i, y: j };
            gridDatas.push(gridData);
        }
    }
    return gridDatas;
}
 
/**
 * 根据行列号获取经纬度范围
 * @param {*} x 列号
 * @param {*} y 行号
 * @param {*} z 级别
 * @returns 
 */
 export function gridToBbox(x,y,z) {
    const x1 = x * 256 * (360 / (Math.pow(2, z) * 256)) - 180;
    const y1 = 90 - y * 256 * (180 / (Math.pow(2, z - 1) * 256));
    const x2 = x1 + 360 / Math.pow(2, z);
    const y2 = y1 + 180 / Math.pow(2, z - 1);
    return [x1, y1, x2, y2];
}

效果在这里插入图片描述

参考:
leaflet 叠加天地图经纬度瓦片绘制网格

<think>好的,用户之前询问了如何实现温州台风网的风场效果,特别是粒子流动和底图的色斑图。现在他们进一步问到底图色斑图的实现方法。我需要详细解释色斑图的生成步骤和相关技术。 首先,用户可能不太清楚色斑图具体指的是什么。色斑图通常是指气象数据中的等值线图或栅格图,用颜色渐变表示不同数值,比如风速或降水量。需要明确解释色斑图的概念,并区分等值线填充和热力图的区别。 接下来,用户需要的是技术实现方案。可能他们已经了解一些地图库,比如Leaflet或Mapbox,但不知道如何将色斑图集成进去。我应该分步骤讲解,从数据处理到可视化,再到与地图的结合。 数据处理部分,用户可能需要使用Python处理原始数据,比如NetCDF或GRIB格式,转换为前端可用的GeoJSON或栅格图片。这里需要提到常用的库,如xarray、netCDF4,以及如何生成等值线或栅格数据。 然后是前端可视化,使用WebGL或Canvas技术。Mapbox GL JS的填充图层和deck.gl的多边形图层都是可行的方案。还需要提到开源库如Turf.js用于生成等值线,或者前端生成等值面的方法。 用户可能关心的还有性能优化,比如数据压缩和动态加载。特别是处理大规模气象数据时,如何减少前端负担是关键。可能需要提到将数据转换为PNG格式,或者使用金字塔结构分片加载。 另外,颜色映射的配置也很重要,需要说明如何根据数据范围设置色带,以及如何在地图缩放时调整细节层次。可能用户对动态调整数据精度不太熟悉,需要给出具体例子或建议。 最后,用户可能需要代码示例来更好地理解实现步骤。使用Mapbox GL JS的例子会比较直观,展示如何添加填充图层和颜色配置。同时,可以提及使用GDAL生成栅格数据的方法,帮助用户处理数据。 总结来说,我需要覆盖色斑图的定义、数据处理方法、前端可视化技术、性能优化策略,并提供具体的代码示例和工具推荐,确保用户能够逐步实现底图的色斑图效果。</think>要实现类似温州台风网的 **底图色斑图**(通常指气象要素的等值线填充图或栅格热力图,例如风速、气压的分布),其核心是将 **离散的气象格点数据** 转换为 **连续的色彩渐变效果**,并叠加在地图上。以下是详细实现方案: --- ### 一、色斑图技术本质 色斑图(等值线填充图)的生成流程为: ``` 原始格点数据 → 插值计算 → 生成等值线/面 → 颜色填充 → 地图叠加 ``` 关键技术点: 1. **数据插值**(将离散点转为连续表面) 2. **等值线生成**(确定颜色边界) 3. **颜色映射**(数值到颜色的映射关系) 4. **高性能渲染**(大数据量下的流畅绘制) --- ### 二、实现步骤与方案 #### 1. **数据准备** - **数据格式**:需要 **经纬度网格点数据**(如 NetCDF、GRIB2 格式),包含每个点的气象要素值(如风速、气压)。 ```python # Python 示例:使用 xarray 读取 NetCDF 数据 import xarray as xr ds = xr.open_dataset('wind_data.nc') u = ds['u_component'] # 经向风速分量 v = ds['v_component'] # 纬向风速分量 speed = np.sqrt(u**2 + v**2) # 计算风速标量 ``` - **数据简化**: - **降采样**:根据地图缩放级别动态调整数据分辨率。 - **格式转换**:将数据转为 **GeoJSON**(矢量)或 **PNG 栅格**(图像)。 --- #### 2. **生成等值线/面** - **方案一:后端生成等值线**(Python + GDAL) ```python # 使用 GDAL 生成等值线(保存为 GeoJSON) from osgeo import gdal, gdal_contour # 将风速数据转为 GeoTIFF driver = gdal.GetDriverByName('GTiff') ds = driver.Create('speed.tif', width, height, 1, gdal.GDT_Float32) ds.GetRasterBand(1).WriteArray(speed) # 生成等值线 gdal_contour(src_ds='speed.tif', dst_filename='contour.geojson', interval=5.0) ``` - **方案二:前端生成等值面**(浏览器内计算) ```javascript // 使用 Turf.js 生成等值线 const gridData = turf.featureCollection(points); // 原始格点数据 const isobands = turf.isobands(gridData, [0, 5, 10, 15], { zProperty: 'speed' }); ``` --- #### 3. **颜色填充** - **方案一:矢量填充(等值线填充)** - 使用 **Mapbox GL 的填充图层**: ```javascript map.addLayer({ id: 'contour-fill', type: 'fill', source: { type: 'geojson', data: 'contour.geojson' }, paint: { 'fill-color': { property: 'speed', // 根据属性值映射颜色 stops: [ [0, '#00f'], // 0 m/s → 蓝色 [15, '#f00'] // 15 m/s → 红色 ] }, 'fill-opacity': 0.5 } }); ``` - **方案二:栅格热力图(WebGL 高性能)** - 使用 **Deck.gl 的 BitmapLayer**: ```javascript new Deck.BitmapLayer({ image: 'wind_speed.png', // 预生成的栅格图 bounds: [minLng, minLat, maxLng, maxLat], colorDomain: [0, 30], // 风速范围 0~30 m/s colorScale: (value) => [ value * 8, // R 255 - value * 8, // G 0, // B 150 // Alpha ] }); ``` --- ### 三、关键技术细节 #### 1. **数据插值优化** - **插值算法**:双线性插值(简单) vs 克里金插值(精确)。 - **Web端实时插值**:使用 [WebAssembly](https://webassembly.org/) 加速计算(如 [geotiff.js](https://geotiffjs.github.io/))。 #### 2. **颜色映射配置** - **色带设计**:参考气象标准(如风速:蓝→黄→红表示低→高)。 - **动态色阶**:根据数据范围自动调整颜色分段。 #### 3. **性能优化** - **数据分块**:将全球数据切分为金字塔瓦片(类似地图瓦片)。 - **WebGL 渲染**:使用 GPU 加速栅格渲染(如 Mapbox GL 的 `raster` 图层)。 --- ### 四、完整代码示例(Mapbox GL + 栅格色斑图) ```html <!-- HTML --> <div id="map" style="width: 100%; height: 600px;"></div> <script src="https://api.mapbox.com/mapbox-gl-js/v2.9.2/mapbox-gl.js"></script> <!-- JavaScript --> <script> mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN'; const map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/dark-v10', center: [121.5, 28.0], zoom: 5 }); // 添加栅格色斑图层 map.on('load', () => { map.addSource('wind-speed', { type: 'image', url: 'wind_speed.png', // 预生成的栅格图(需包含元数据) coordinates: [ [115.0, 31.0], // 左上角经纬度 [125.0, 31.0], // 右上 [125.0, 25.0], // 右下 [115.0, 25.0] // 左下 ] }); map.addLayer({ id: 'speed-layer', type: 'raster', source: 'wind-speed', paint: { 'raster-opacity': 0.7, 'raster-color': [ 'interpolate', ['linear'], ['raster-value'], 0, '#313695', // 颜色映射规则 15, '#ffffbf', 30, '#a50026' ] } }); }); </script> ``` --- ### 五、工具推荐 1. **数据处理**: - [GDAL](https://gdal.org/):生成等值线、栅格转换 - [Python xarray](https://xarray.pydata.org/):处理 NetCDF/GRIB 数据 2. **前端渲染**: - [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/):高性能栅格/矢量叠加 - [Deck.gl](https://deck.gl/):WebGL 大数据渲染 3. **颜色设计**: - [ColorBrewer](https://colorbrewer2.org/):科学配色方案 --- ### 难点总结 - **数据与地图对齐**:确保栅格图的坐标系(WGS84)与地图精确匹配。 - **动态更新**:实时更新色斑图时需注意内存释放和性能平衡。 - **视觉层次**:色斑图需与地图底图、风场粒子图层协调叠加(透明度、颜色对比)。 如果需要更具体的某一步骤(如 GDAL 生成栅格数据),可以进一步展开说明!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值