mapboxgl 加载瓦片网格


import mapboxgl from "mapbox-gl";
export default class GridLayer {
  constructor(map) {
    this.map = map;
    this.gridSourceId = "grid-source";
    this.gridLayerId = "grid-layer";
    this.labelSourceId = "label-source";
    this.labelLayerId = "label-layer";

    this.initGrid();
    this.map.on("moveend", () => this.updateGrid());
    this.map.on("zoomend", () => this.updateGrid());
  }

  initGrid() {
    this.map.addSource(this.gridSourceId, {
      type: "geojson",
      data: this.createGridData()
    });

    this.map.addLayer({
      id: this.gridLayerId,
      type: "line",
      source: this.gridSourceId,
      layout: {},
      paint: {
        "line-color": "#888",
        "line-width": 1
      }
    });

    // label文本显示需要在样式中设置glyphs
    this.map.addSource(this.labelSourceId, {
      type: "geojson",
      data: this.createLabelData()
    });

    this.map.addLayer({
      id: this.labelLayerId,
      type: "symbol",
      source: this.labelSourceId,
      layout: {
        "text-field": ["get", "text"],
        "text-size": 24,
        "text-offset": [0, 0],
        "text-font": ["Arial Regular"]
      },
      paint: {
        "text-color": "#fff", // 文本的颜色(可选,默认值为 #000000)
        "text-halo-color": "rgb(190,190,190)", // 文本的光晕颜色(可选,默认值为 rgba(0,0,0,0))
        "text-halo-width": 3 // 文本的光晕宽度(可选,值 >= 0,默认值为 0,单位:像素)
      }
    });
  }

  createGridData() {
    const bounds = this.map.getBounds();
    const zoom = Math.floor(this.map.getZoom());
    const tileCount = Math.pow(2, zoom);

    const lngStep = 360 / tileCount;
    const minLat = -85.05112878;
    const maxLat = 85.05112878;

    const minLng = Math.floor(bounds.getWest() / lngStep) * lngStep;
    const maxLng = Math.ceil(bounds.getEast() / lngStep) * lngStep;

    const lines = [];

    for (let lng = minLng; lng <= maxLng; lng += lngStep) {
      lines.push({
        type: "Feature",
        geometry: {
          type: "LineString",
          coordinates: [
            [lng, minLat],
            [lng, maxLat]
          ]
        }
      });
    }

    for (let y = 0; y <= tileCount; y++) {
      const lat = this.yTile2lat(y, zoom);
      lines.push({
        type: "Feature",
        geometry: {
          type: "LineString",
          coordinates: [
            [minLng, lat],
            [maxLng, lat]
          ]
        }
      });
    }

    return {
      type: "FeatureCollection",
      features: lines
    };
  }

  createLabelData() {
    const bounds = this.map.getBounds();
    const zoom = Math.floor(this.map.getZoom());
    const tileCount = Math.pow(2, zoom);

    const lngStep = 360 / tileCount;
    // const minLat = -85.05112878;
    // const maxLat = 85.05112878;
    // const minLng = Math.floor(bounds.getWest() / lngStep) * lngStep;
    // const maxLng = Math.ceil(bounds.getEast() / lngStep) * lngStep;

    // 通过经纬度计算瓦片信息,保证只绘制可视域范围内的瓦片
    let minxyz = this.lngLat2Tile([bounds.getWest(), bounds.getSouth()], zoom);
    let maxxyz = this.lngLat2Tile([bounds.getEast(), bounds.getNorth()], zoom);

    const labels = [];
    for (let x = minxyz.x; x <= maxxyz.x; x++) {
      for (let y = maxxyz.y; y <= minxyz.y; y++) {
        const lng = this.xTile2lng(x, zoom);
        const lat = this.yTile2lat(y, zoom);
        const nextLng = this.xTile2lng(x + 1, zoom);
        const nextLat = this.yTile2lat(y + 1, zoom);
        if (
          (lng >= bounds.getWest() || nextLng <= bounds.getEast()) &&
          (lat >= bounds.getSouth() || nextLat <= bounds.getNorth())
        ) {
          labels.push({
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [(lng + nextLng) / 2, (lat + nextLat) / 2]
            },
            properties: {
              text: `Z: ${zoom}\nX: ${x}\nY: ${y}`
            }
          });
        }
      }
    }

    return {
      type: "FeatureCollection",
      features: labels
    };
  }

  //经纬度转瓦片序列号
  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 };
  }

  xTile2lng(x, zoom) {
    return (x / Math.pow(2, zoom)) * 360 - 180;
  }

  yTile2lat(y, zoom) {
    const n = Math.PI - (2 * Math.PI * y) / Math.pow(2, zoom);
    return (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
  }

  updateGrid() {
    this.map.getSource(this.gridSourceId).setData(this.createGridData());
    this.map.getSource(this.labelSourceId).setData(this.createLabelData());
  }

  removeGridLayer() {
    this.map.removeLayer(this.gridLayerId);
    this.map.removeSource(this.gridSourceId);
    this.map.removeLayer(this.labelLayerId);
    this.map.removeSource(this.labelSourceId);
  }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值