mapbox地图与天地图底图相互切换

添加天地图底图,是通过addLayerToGroup()方式添加,而切换为mapbox底图(例如深色图,户外图)是使用setStyle()方法将地图样式设置为新样式。

在实践中发现这样直接切换,会使地图上原有的图层被移除,那么怎么实现mapbox地图与天地图底图相互切换,且保留地图上原有图层呢?

整体思路:

先定义图层组,在初始化底图时添加所有的图层组(占位图层),便于切换图层时,保证图层顺序。

切换地图样式(切换为mapbox底图)

使用传入的map对象和styleID参数,构建一个GET请求的URL,其中包含了访问地图样式所需的访问令牌(access token)。以此获取指定样式(例如mapbox://styles/mapbox/streets-v11)的数据。

使用axios库发送GET请求,并使用解构赋值将返回的响应数据中的data字段赋值给newStyle变量。

获取当前地图样式的配置信息,保存在currentStyle变量中。

将当前样式中的所有数据源(sources)复制到新样式的数据源中,以确保保留了原有的数据源。

查找需要保留在新样式中的图层的索引位置。

从当前样式中筛选出需要保留的应用程序图层(app layers)。这些图层是那些具有不同数据源设置的图层。
构建新的图层数组,按照以下顺序排列:将0到labelIndex之间的图层拷贝到新数组中,然后将所有图层拷贝到新数组中,最后将labelIndex到倒数第二个图层拷贝到新数组中。

使用map.setStyle(newStyle)方法将地图样式设置为新样式。

切换为天地图底图时

从当前样式中筛选出需要保留的图层,例如图层组中的图层,以及手动添加的其他图层

去除掉当前样式中不需要的属性

使用map.setStyle()方法将地图样式设置为新样式。

然后再使用addLayerToGroup()方式添加天地图底图

具体实现

1.首先定义图层组

需要注意,在给图层命名时需要便于筛选
例如命名时,名称都是“TD_BASE_XXXXXX”格式

 const LAYERS_GROUP = {
  TD_BASE_MAP: 'TD_BASE_MAP', //底图
  TD_BASE_LABEL_MAP: 'TD_BASE_LABEL_MAP', //地图标注
};
2.初始化地图并添加所有的图层组(占位图层)

天地图图源

// 天地图影像图
const TD_IMG_URL = [
  'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t1.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t2.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t3.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t4.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t5.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t6.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'https://t7.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
];
// 天地图标注图层
const TD_CIA_URL = [
  'http://t0.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t1.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t2.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t3.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t4.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t5.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t6.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
  'http://t7.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=你自己的天地图token',
];

给图层组添加图层方法

/**
 * mapbox移除指定图层
 * @param {string} layerId 图层id
 */
 REMOVE_MAPBOX_LAYER(layerId, MAP) {
  if (MAP.getLayer(layerId)) {
    MAP.removeLayer(layerId);
    MAP.removeSource(layerId);
  }
}
/**
 * mapbox切换底图
 * @param { String } id 要切换的底图类型
 */
 CHANGE_MAPBOX_BASE_LAYER = (MAP) => {
  const layerId = LAYERS_GROUP.TD_BASE_MAP;
  let sources;

  // 移除原来图层
  REMOVE_MAPBOX_LAYER(layerId, MAP);

  sources = {
    TD_IMG: {
      id: layerId,
      type: 'raster',
      tiles: TD_IMG_URL,
      tileSize: 256,
    },
  };

  let layers = {
    id: layerId,
    type: 'raster',
    source: sources.TD_IMG,
  };

  MAP.addLayerToGroup(layerId, layers);
};

/**
 * mapbox切换标注
 * @param { String } id 要切换的底图类型
 */
CHANGE_MAPBOX_BASE_LABEL_LAYER = (MAP) => {
  const layerId = LAYERS_GROUP.TD_BASE_LABEL_MAP;
  let sources;

  // 移除原来图层
  REMOVE_MAPBOX_LAYER(layerId, MAP);

  sources = {
    TD_IMG: {
      id: layerId,
      type: 'raster',
      tiles: TD_CIA_URL,
      tileSize: 256,
    },
  };

  let layers = {
    id: layerId,
    type: 'raster',
    source: sources.TD_IMG,
  };

  MAP.addLayerToGroup(layerId, layers);
};

地图初始化

mapInit() {
  map2d = new MapboxGL.Map({
    container: 'map',
    style: {
      sources: {},
      version: 8,
      glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
      layers: [],
    },
    antialias: true, // 启用抗锯齿以改善三维地形的渲染效果
    
  });

  const mapContainer = document.getElementById('map');

  

  map2d.on('load', function () {
    // 添加所有的图层组(占位图层)
    _.map(LAYERS_GROUP, (id) => {
      map2d.addLayerGroup(id);
    });
    // 添加底图

    CHANGE_MAPBOX_BASE_LAYER(map2d);
    CHANGE_MAPBOX_BASE_LABEL_LAYER(map2d);
  });
  

  return map2d;
}

进行到这一步以后,地图上显示天地图影像图以及标注
天地图影像图以及标注

3.在现有地图上添加了其他图层(点,线,面)

注意,为了使切换底图时,方便过滤出这些图层,在给图层id命名时需要需要便于筛选
例如:“MAP_LAYER_XXXXXX”
此处对添加其他图层方法就不做赘述了
添加后的效果:现有地图上添加了其他图层

4.将现有地图切换为mapbox底图

获取当前地图样式的配置信息,保存在currentStyle变量中。

将当前样式中的所有数据源(sources)复制到新样式的数据源中,以确保保留了原有的数据源。

查找需要保留在新样式中的图层的索引位置。这里通过过滤掉newStyle.layers数组中id不包含’-label’的图层。为的是去掉mapbox的文字标注,因为我们这里使用的是天地图的标注。

从当前样式中筛选出需要保留的应用程序图层(app layers)。这里需要保留id中包含 ‘TD_BASE’ 或id中包含 ‘MAP_LAYER’ 的图层(这里就是前面说的命名时需要特别注意的原因)

这些图层是那些具有不同数据源设置的图层。

构建新的图层数组,然后将所有图层拷贝到新数组中

使用map.setStyle(newStyle)方法将地图样式设置为新样式。

/**
 * 切换地图样式(mapbox底图)
 * @param {*} data Mapbox地图样式
 * @param {*} MAP 地图实例
 */
mapStyleSwitcher = (data, MAP) => {
  let token = '你自己的mapbox 的 Token';

  axios
    .get(`https://api.mapbox.com/styles/v1/${data}?access_token=${token}`)
    .then((result) => {
      const { data: newStyle } = result;
      const currentStyle = MAP.getStyle();

      newStyle.sources = Object.assign({}, currentStyle.sources, newStyle.sources);

      let Layers = newStyle.layers.filter((el) => {
        //去掉mapbox底图地名标注
        return !el.id.includes('-label');
      });

      const appLayers = currentStyle.layers.filter((el) => {
        return (
          (el.source &&
            el.source != 'mapbox://mapbox.satellite' &&
            el.source != 'mapbox' &&
            el.source != 'composite') ||
          el.id.includes('TD_BASE') ||
          el.id.includes('MAP_LAYER')
        );
      });

      Layers = [...Layers, ...appLayers];
      newStyle.layers = Layers;
      MAP.setStyle(newStyle);
    })
    .catch((error) => {
      console.error(error);
    });
};

调用方法:例如切换为mapbox深色图

mapStyleSwitcher('mapbox/dark-v11', map);

切换后的效果:mapbox深色图

5.切换回天地图底图

从当前样式中筛选出需要保留的图层,例如图层组中的图层,以及手动添加的其他图层:依旧是需要保留id中包含 ‘TD_BASE’ 或id中包含 ‘MAP_LAYER’ 的图层

去除掉当前样式中不需要的属性

使用map.setStyle()方法将地图样式设置为新样式。

然后再使用addLayerToGroup()方式添加天地图底图

/**
 * 重置地图样式(切换为天地图底图时使用)
 * @param {*} MAP 地图实例
 */
 mapStyleReset = (MAP) => {
  const currentStyle = MAP.getStyle();

  const appLayers = currentStyle.layers.filter((el) => {
    return el.id.includes('TD_BASE') || el.id.includes('MAP_LAYER');
  });

  // console.log(appLayers);

  let newStyle = {};

  newStyle.layers = [...appLayers];
  newStyle.glyphs = 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf';
  newStyle.version = 8;
  newStyle.sources = currentStyle.sources;

  delete newStyle.sprite;

  MAP.setStyle(newStyle);
};

调用方法:

mapStyleReset(map);
//重新添加底图到图层组中
CHANGE_MAPBOX_BASE_LAYER(map)

效果:
重新添加底图
至此就实现了mapbox地图与天地图底图相互切换,且保留地图上原有图层的功能。
希望可以帮助遇到此类问题的朋友们提供到一些解决思路

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值