Mapbox GL-突出显示功能和queryRenderedFeatures,同时允许更改底图样式

问题描述

我需要能够使用this example中所示的Mapbox GL突出显示边界框中的要素。我的地图还需要具有更改样式图层的功能,例如将基本样式从mapbox://styles/mapbox/light-v10更改为mapbox://styles/mapbox/satellite-v9。这具有挑战性,因为Mapbox GL本身不支持“底图”的概念,例如传单。

我的解决方案经过大量搜索(我相信最终我遵循了github问题中发布的解决方法)涉及

  1. 使用map.on('style.load')代替示例中的map.on('load')(我相信map.on('style.load')不是其公共API的一部分,但我可能是错的),>

  2. 遍历一系列源/图层(请参见下面的代码vectorTileLayers),以便在每次加载新样式时向地图添加矢量图块图层。

这在某些方面对我很有用-我可以向数组添加任意数量的矢量图块源,并且如果更改了基本样式,它们也会全部添加回地图。但是,如果将源/图层以数组形式添加到地图中并进行迭代,如下图所示,则无法按照Mapbox提供的示例添加查询功能。边界功能有效,但是在绘制并释放该功能时,通过运行下面的代码片段,我看到了错误显示。

这是我的实际问题的简化版本,它将允许其他人运行和操纵代码。实际上,我要添加自己的矢量平铺图层(存储在vectorTileLayers数组中,该图层可以正常工作。当尝试添加具有相同来源和不同样式的另一层时,如示例所示, “我无法实际查询所需的图层。将不胜感激。请仅供参考-此代码段中未显示可切换图层的按钮,但解决问题并不重要。

mapboxgl.accessToken = 'pk.eyJ1IjoiamFtZXljc21pdGgiLCJhIjoiY2p4NTRzdTczMDA1dzRhbXBzdmFpZXV6eCJ9.-k7Um-xmYy4xhNDN6kDvpg';
    var map = new mapboxgl.Map({
      container: 'map',style: 'mapbox://styles/mapbox/light-v10',center: [-98,38.88],minZoom: 2,zoom: 3
    });

    var vectorTileLayers = [{
        source: {
          type: 'vector',url: 'mapbox://mapbox.82pkq93d'
        },layer: {
          id: 'counties',type: 'fill',source: 'counties','source-layer': 'original',paint: {
            'fill-outline-color': 'rgba(0,0.1)','fill-color': 'rgba(0,0.1)'
          },}
      },{
        source: {
          type: 'vector',layer: {
          id: 'counties-highlighted',paint: {
            'fill-outline-color': '#484896','fill-color': '#6e599f','fill-opacity': 0.75
          },filter: ['in','FIPS','']
        }
      }
    ]

    map.on('style.load',function() {
      for (var i = 0; i < vectorTileLayers.length; i++) {
        var tileLayer = vectorTileLayers[i];
        map.addSource(tileLayer.layer.source,tileLayer.source);
        map.addLayer(tileLayer.layer);
      }

      var layerList = document.getElementById('basemapmenu');
      var inputs = layerList.getElementsByTagName('input');

      function switchLayer(layer) {
        var layerId = layer.target.id;
        map.setStyle('mapbox://styles/mapbox/' + layerId);
      }
      for (var i = 0; i < inputs.length; i++) {
        inputs[i].onclick = switchLayer;
      }

    });

    // Disable default box zooming.
    map.boxZoom.disable();

    // Create a popup,but don't add it to the map yet.
    var popup = new mapboxgl.Popup({
      closeButton: false
    });

    var canvas = map.getCanvasContainer();

    var start;
    var current;
    var box;

    canvas.addEventListener('mousedown',mouseDown,true);
    // Return the xy coordinates of the mouse position
    function mousePos(e) {
      var rect = canvas.getBoundingClientRect();
      return new mapboxgl.Point(
        e.clientX - rect.left - canvas.clientLeft,e.clientY - rect.top - canvas.clientTop
      );
    }

    function mouseDown(e) {
      // Continue the rest of the function if the shiftkey is pressed.
      if (!(e.shiftKey && e.button === 0)) return;

      // Disable default drag zooming when the shift key is held down.
      map.dragPan.disable();

      // Call functions for the following events
      document.addEventListener('mousemove',onMouseMove);
      document.addEventListener('mouseup',onMouseUp);
      document.addEventListener('keydown',onKeyDown);

      // Capture the first xy coordinates
      start = mousePos(e);
    }

    function onMouseMove(e) {
      // Capture the ongoing xy coordinates
      current = mousePos(e);

      // Append the box element if it doesnt exist
      if (!box) {
        box = document.createElement('div');
        box.classList.add('boxdraw');
        canvas.appendChild(box);
      }

      var minX = Math.min(start.x,current.x),maxX = Math.max(start.x,minY = Math.min(start.y,current.y),maxY = Math.max(start.y,current.y);

      // Adjust width and xy position of the box element ongoing
      var pos = 'translate(' + minX + 'px,' + minY + 'px)';
      box.style.transform = pos;
      box.style.WebkitTransform = pos;
      box.style.width = maxX - minX + 'px';
      box.style.height = maxY - minY + 'px';
    }

    function onMouseUp(e) {
      // Capture xy coordinates
      finish([start,mousePos(e)]);
    }

    function onKeyDown(e) {
      // If the ESC key is pressed
      if (e.keyCode === 27) finish();
    }

    function finish(bbox) {
      // Remove these events now that finish has been called.
      document.removeEventListener('mousemove',onMouseMove);
      document.removeEventListener('keydown',onKeyDown);
      document.removeEventListener('mouseup',onMouseUp);

      if (box) {
        box.parentNode.removeChild(box);
        box = null;
      }

      // If bbox exists. use this value as the argument for `queryRenderedFeatures`
      if (bbox) {
        var features = map.queryRenderedFeatures(bbox,{
          layers: ['counties']
        });

        if (features.length >= 1000) {
          return window.alert('Select a smaller number of features');
        }

        // Run through the selected features and set a filter
        // to match features with unique FIPS codes to activate
        // the `counties-highlighted` layer.
        var filter = features.reduce(
          function(memo,feature) {
            memo.push(feature.properties.FIPS);
            return memo;
          },['in','FIPS']
        );

        map.setFilter('counties-highlighted',filter);
      }

      map.dragPan.enable();
    }

    map.on('mousemove',function(e) {
      var features = map.queryRenderedFeatures(e.point,{
        layers: ['counties-highlighted']
      });
      // Change the cursor style as a UI indicator.
      map.getCanvas().style.cursor = features.length ? 'pointer' : '';

      if (!features.length) {
        popup.remove();
        return;
      }

      var feature = features[0];

      popup
        .setLngLat(e.lngLat)
        .setText(feature.properties.COUNTY)
        .addTo(map);
    });
body {
  margin: 0;
  padding: 0;
}

#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

#basemapmenu {
    position: absolute;
    display: inline-block;
    background-color: transparent;
    bottom: 0;
    left: 0;
    margin-left: 10px;
    margin-bottom: 40px;
}

.boxdraw {
  background: rgba(56,135,190,0.1);
  border: 2px solid #3887be;
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet"/>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>

<div id="map"></div>

<div id='basemapmenu'>
    <input id='light-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Light' checked='checked'>
    <input id='dark-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Dark'>
    <input id='satellite-v9' class='btn btn-outline-primary' type='button' name='rtoggle' value='Satellite'>
  </div>

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)