Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
504 views
in Technique[技术] by (71.8m points)

mapbox - Highlighting Fill-Extrude Features on Hover after tilting?

I want to highlight fill-extrusion features when hovered over them. The styling related to this is straight-forward using expressions and feature state, but I am having trouble retrieving the correct features.

There is code available online to change the feature state when hovered over, and it seems straight-forward enough, so I adapted it:

var hover_id = null;
const feature_state = { hover: true }

map.on('mousemove', '3d-buildings', (e) => {
  
    // Get features under cursor, following render order
    const features = map.queryRenderedFeatures(e.point);

    // Check that features are not empty
    if (features.length > 0) {

        // Clean up previously hovered feature
        if (hover_id) {
            map.removeFeatureState({source: "composite", sourceLayer: 'building', id: hover_id});
        }

        // Set feature state of the new hovered feature
        hover_id = features[0].id;
        map.setFeatureState({source: 'composite', sourceLayer: 'building', id: hover_id}, feature_state);

        console.log(hover_id)
  }
});

While this works well initially, it stops working as soon as I tilt the camera using the right mouse button. After tilting, the foremost element no longer gets selected (something else seems to get selected and an ID gets printed out, but nothing shows up on the map and no error is thrown). On a related note, the correct feature only gets selected after zooming in quite far - there is a large zoom range where the buildings already get rendered to the screen, but seem to not get picked up by queryRenderedFeatures. Is this expected behaviour?

Expected behaviour: map.queryRenderedFeatures(...)[0] selects the foremost feature, independent of the camera tilt.

What could be a possible reason for the camera tilt influencing the feature selection? Is this a bug or am I misusing the API?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think the issue you’re facing has nothing to do with tilt but with the fact that you’re adding and removing the state instead of changing the value of the state. The state must be declared in the layer definition, change the color with a expression, and then you only need to change the value of the state.

Here you have a fiddle I have created to show how to change color of fill extrusions on mouse over/out

enter image description here

Relevant code is this:

        let mapConfig = {
          NYC: {
            origin: [-74.044514, 40.689259, 39],
            center: [-74.0137, 40.70346, 0],
            zoom: 16.2,
            pitch: 60,
            bearing: 35
          }
        }

        mapboxgl.accessToken = 'PUT YOUR TOKEN HERE';
        let point = mapConfig.NYC;
        var map = new mapboxgl.Map({
          style: 'mapbox://styles/mapbox/streets-v11',
          center: point.center,
          zoom: point.zoom,
          pitch: point.pitch,
          bearing: point.bearing,
          container: 'map',
          antialias: true,
          hash: true
        });

        map.on('style.load', function() {

          if (map.getSource('composite')) {
            map.addLayer({
              'id': '3d-buildings',
              'source': 'composite',
              'source-layer': 'building',
              'type': 'fill-extrusion',
              'minzoom': 14,
              'paint': {
                'fill-extrusion-color': [
                  'case',
                  ['boolean', ['feature-state', 'hover'], false],
                  '#ff0000',
                  '#ddd'
                ],
                'fill-extrusion-height': ["number", ["get", "height"], 5],
                'fill-extrusion-base': ["number", ["get", "min_height"], 0],
                'fill-extrusion-opacity': 1
              }
            }, 'road-label');
          }

          let fHover;

          map.on('mousemove', function(e) {
            //157001066
            var features = map.queryRenderedFeatures(e.point, {
              layers: ['3d-buildings']
            });
            if (features[0]) {
              mouseout();
              mouseover(features[0]);
            } else {
              mouseout();
            }

          });

          map.on('mouseout', function(e) {
            mouseout();
          });

          function mouseout() {
            if (!fHover) return;
            map.getCanvasContainer().style.cursor = 'default';
            map.setFeatureState({
              source: fHover.source,
              sourceLayer: fHover.sourceLayer,
              id: fHover.id
            }, {
              hover: false
            });

          }

          function mouseover(feature) {
            fHover = feature;
            map.getCanvasContainer().style.cursor = 'pointer';

            map.setFeatureState({
              source: fHover.source,
              sourceLayer: fHover.sourceLayer,
              id: fHover.id
            }, {
              hover: true
            });
          }


        });

If this answer solves your question, please mark it as answer accepted in that way it will also help other users to know it was the right solution.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...