美文网首页
mapbox画瓦片网格

mapbox画瓦片网格

作者: 姜治宇 | 来源:发表于2023-05-10 11:31 被阅读0次

    经纬度转瓦片数字

    瓦片栅格,就是我们在地图上打格子,比如zoom为0时是顶级,你画几个格子,然后标上行列号,比如0-0,0-1,然后随着zoom的不断变化,格子也不断裂变,行列号也不断变大。
    那么,我们在地图上画网格,如何跟瓦片栅格的数字一致呢?
    瓦片栅格数字,跟经纬度有个换算关系:

      import mapboxgl from 'mapbox-gl';
      import * as turf from '@turf/turf';
    ...
      //经纬度转瓦片序列号
      lngLat2Tile(coordinates, zoom) {
        const { x, y } = mapboxgl.MercatorCoordinate.fromLngLat({
          lng: coordinates[0],
          lat: coordinates[1],
        });
    
        const scale = Math.pow(2, zoom);
        const tileX = Math.floor(x * scale);
        const tileY = Math.floor(y * scale);
        return { x: tileX, y: tileY, z: zoom };
      }
    

    瓦片数字转bbox

    那么知道了当前瓦片的数字,如何反推经纬度呢?实际上,一个瓦片对应的是一个格子,那么,我们要得到的,其实是一个边界信息。

    var d2r = Math.PI / 180,
      r2d = 180 / Math.PI;
    
    /**
     * Get the bbox of a tile
     *
     * @name tileToBBOX
     * @param {Array<number>} tile
     * @returns {Array<number>} bbox
     * @example
     * var bbox = tileToBBOX([5, 10, 10])
     * //=bbox
     */
    function tileToBBOX(tile) {
      var e = tile2lon(tile[0] + 1, tile[2]);
      var w = tile2lon(tile[0], tile[2]);
      var s = tile2lat(tile[1] + 1, tile[2]);
      var n = tile2lat(tile[1], tile[2]);
      return [w, s, e, n];
    }
    function tile2lon(x, z) {
      return (x / Math.pow(2, z)) * 360 - 180;
    }
    
    function tile2lat(y, z) {
      var n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z);
      return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
    }
    
    export default {
      tileToBBOX: tileToBBOX,
    };
    

    拿到了这个边界,我们可以借助turf库,拿到格子的坐标信息,这样就可以画出这个格子了。

      import mapboxgl from 'mapbox-gl';
      import * as turf from '@turf/turf';
      import tilebelt from '../common/tilebelt';
    ...
      initGrid() {
          const key = 'draw-grid';
          this.mapboxService.map.addSource(key, {
            type: 'geojson',
            data: {
              type: 'FeatureCollection',
              features: [],
            },
          });
    
          this.mapboxService.map.addLayer({
            id: key,
            type: 'fill',
            source: key,
            paint: {
             // 'fill-color': 'orange',
             // 'fill-opacity': 0.3,
            },
          });
        
      }
      drawGrid(x,y,z){
          const bbox = tilebelt.tileToBBOX([x, y, z]);
          console.log('边界信息>>>', bbox);
          const rect = turf.bboxPolygon([bbox[0], bbox[1], bbox[2], bbox[3]]);
          console.log('rect', rect);
          const featuresArr = [
            {
              type: 'Feature',
              geometry: {
                type: 'Polygon',
                coordinates: rect.geometry.coordinates,
              },
            },
          ];
    
          this.renderTaskGrid('draw-grid', featuresArr, {
            'fill-color': 'orange',
            'fill-opacity': 0.3,
          });
      }
    
      renderTaskGrid(key, featureArr, options) {
        //渲染任务格子
        console.log('key', key);
        if (this.mapboxService.map.getSource(key)) {
          this.mapboxService.map.getSource(key).setData({
            //设置数据
            type: 'FeatureCollection',
            features: featureArr,
          });
          // this.mapboxService.map.setPaintProperty(key, 'fill-color', color); //设置格子颜色
          if (Object.keys(options).length > 0) {
            Object.keys(options).map((v) => {
              this.mapboxService.map.setPaintProperty(key, v, options[v]);
            });
          }
    
        }
      }
    

    格子的外边界

    我们画出瓦片的格子其实是填充的正方形,mapbox定义的fill类型的外边界stroke,默认就是1,无法改变。所以,我们要打网格,还要单独画line。

    import mapboxgl from 'mapbox-gl';
    import * as turf from '@turf/turf';
    // import { CustomSource } from '../common/customSource';
    import tilebelt from '../common/tilebelt';
    ...
      polygonKeys = [
          'active-taskgrid',
          'draw-taskgrid-1',
          'draw-taskgrid-2',
      ];
      lineKeys = ['task-grid-draw-line'];
      initGrid() {
        //格子包括边框和填充,polygon无法改变stroke笔触
        this.mapboxService.map.addSource(this.lineKeys[0], {
          type: 'geojson',
          data: {
            type: 'FeatureCollection',
            features: [],
          },
        });
    
        this.mapboxService.map.addLayer({
          id: this.lineKeys[0],
          type: 'line',
          source: this.lineKeys[0],
          paint: {
            'line-color': 'white',
            'line-width': 2,
          },
        });
        //填充
        for (const key of this.polygonKeys) {
          this.mapboxService.map.addSource(key, {
            type: 'geojson',
            data: {
              type: 'FeatureCollection',
              features: [],
            },
          });
    
          this.mapboxService.map.addLayer({
            id: key,
            type: 'fill',
            source: key,
            paint: {
              // 'fill-color': 'orange',
              'fill-opacity': 0,
            },
          });
        }
    
      }
    
      async drawGrid() {
        const arr = this.getBBox(); //所有可见的格子
        this.drawLine(arr); //画边界线
        const res = [
          {
            name: '格子1',
            status: 1,
            desc: '已完成',
            grid: { x: 27239, y: 12810, z: 15 },
          },
          {
            name: '格子2',
            status: 2,
            desc: '二次标注',
            grid: { x: 27239, y: 12812, z: 15 },
          },
          {
            name:'格子3',
            status:1,
            desc:'已完成',
            grid:{ x: 27244, y: 12809, z: 15 },
          }
        ];
        this.drawPolygon(res);
      }
      clearGrid() {
        this.clearLine();
        this.clearPolygon();
      }
      getBBox() {
        const bboxArr: any = [];
        const arr: any =
          this.mapboxService.map.style._sourceCaches[
            'other:img_tiles'
          ].getVisibleCoordinates();
        // const arr = this.dataSource;
        if (arr && arr.length > 0) {
          for (const item of arr) {
            if (item.overscaledZ === 15) {
              // this.drawGrid(item.canonical.x,item.canonical.y,item.canonical.z,'red');
              const x = item.canonical.x;
              const y = item.canonical.y;
              const z = item.canonical.z;
              const bbox = tilebelt.tileToBBOX([x, y, z]);
              bboxArr.push(bbox);
            }
          }
        }
        return bboxArr;
      }
      drawLine(arr) { //画格子的边界线
        const lineArr: any = [];
    
        if (arr && arr.length > 0) {
          for (const bbox of arr) {
            const line1 = {
              type: 'Feature',
              geometry: {
                type: 'LineString',
                coordinates: [
                  [bbox[0], bbox[1]],
                  [bbox[2], bbox[1]],
                ],
              },
            };
            const line2 = {
              type: 'Feature',
              geometry: {
                type: 'LineString',
                coordinates: [
                  [bbox[0], bbox[1]],
    
                  [bbox[0], bbox[3]],
                ],
              },
            };
            lineArr.push(line1);
            lineArr.push(line2);
          }
          this.renderTaskGrid(this.lineKeys[0], lineArr, {});
        }
      }
    
      drawPolygon(arr) {//画填充图形
        const featuresArr: any = [];
        const featuresArr2: any = [];
        // const arr = this.getBBox();
        if (arr && arr.length > 0) {
          for (const item of arr) {
            const bbox = tilebelt.tileToBBOX([
              item.grid.x,
              item.grid.y,
              item.grid.z,
            ]);
            const rect = turf.bboxPolygon([bbox[0], bbox[1], bbox[2], bbox[3]]);
            console.log('rect', rect);
    
            const feature = {
              type: 'Feature',
              geometry: {
                type: 'Polygon',
                coordinates: rect.geometry.coordinates,
              },
            };
            if (item.status === 1) {
              featuresArr.push(feature);
            } else {
              featuresArr2.push(feature);
            }
          }
    
          this.renderTaskGrid(this.polygonKeys[1], featuresArr, {
            'fill-color': '#0EBC71',
            'fill-opacity': 0.3,
          }); //画图形
          this.renderTaskGrid(this.polygonKeys[2], featuresArr2, {
            'fill-color': '#5A49F6',
            'fill-opacity': 0.3,
          }); //画图形
        }
      }
      clearLine() {
        this.renderTaskGrid(this.lineKeys[0], [], {});
      }
      clearPolygon() {
        for (const key of this.polygonKeys) {
          this.renderTaskGrid(key, [], {}); //画图形
        }
      }
    

    相关文章

      网友评论

          本文标题:mapbox画瓦片网格

          本文链接:https://www.haomeiwen.com/subject/ahzdsdtx.html