mapboxmapbox-gl

Is there any way to give different cursor styles on hover for every feature on same layer in mapbox?


I am looking to change the cursor style on hover that will be dependent on some property value for each and every feature rendering on same layer.What is happening right now that the style of cursor is getting changed for all the features within same layer.I want to control this.


Solution

  • Yes, that's feasible. For that you need to query the features under the mouse pointer, and then decide what is the attribute you will use to filter only some features to differentiate the behavior.

    I have drafted for you a fiddle on how to change color and pointer on mouse over, where I have added a filter for only one feature id among all of the buildings in NYC, that will become red changing its state ('hover ; true') and the mouse pointer is changed to map.getCanvasContainer().style.cursor = 'pointer'.

    enter image description here

    This is the relevant code:

        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 HERE YOUR TOKEN';
        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('click', function(e) {
            var features = map.queryRenderedFeatures(e.point, {
              layers: ['3d-buildings']
            });
            console.log(features[0].id);
          })
    
          map.on('mousemove', function(e) {
            var features = map.queryRenderedFeatures(e.point, {
              layers: ['3d-buildings']
            });
            //we will change pointer and color for 42455719
            if (features[0] && features[0].id == 42455719) {
              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
            });
          }
    
        });
    

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