Doing some tests, trying to let user click on a COUNTY and all counties belonging to STATE x get highlighted.

You can see running here

var map = new mapboxgl.Map({
        container: 'map',
        style: {
            "version": 8,
            "name": "blank",
            "sources": {
                "empty": {
                    "type": "vector",
                    "url": ""
            "layers": [{
                "id": "background",
                "type": "background",
                "paint": {
                    "background-color": "#1d1f20"
        center: [-82, 39],
        zoom: 3,
        debug: 2
    var hoveredStateId = null;

    map.on('load', function() {
        map.addSource("counties", {
            "type": "vector",
            "url": "mapbox://reyemtm.28b260nr"

        // The feature-state dependent fill-opacity expression will render the hover effect
        //  when a feature's hover state is set to true.
            "id": "fill",
            "type": "fill",
            "source": "counties",
            "source-layer": "us_counties-8xelrv",
            "layout": {},
            "paint": {
                "fill-color": ["case", ["boolean", ["feature-state", "hover"], false], "whitesmoke", "firebrick"],
                "fill-opacity": 1

        function getUniqueFeatures(array, comparatorProperty) {

            var existingFeatureKeys = {};
            var uniqueFeatures = array.filter(function(el) {
                if (existingFeatureKeys[el.properties[comparatorProperty]]) {
                    return false;
                } else {
                    existingFeatureKeys[el.properties[comparatorProperty]] = true;
                    return true;

            return uniqueFeatures;

        map.on("click", "fill", function(e) {
            if (e.features.length > 0) {

                var state_code = e.features[0].properties.STATE;
                var relatedFeatures = map.querySourceFeatures('counties', {
                    sourceLayer: 'us_counties-8xelrv',
                    filter: ['==', 'STATE', state_code]

                var uniqueFeatures_state = getUniqueFeatures(relatedFeatures, "STATE");
                var uniqueFeatures_id = getUniqueFeatures(relatedFeatures, "id");

                relatedFeatures.forEach(function(f) {
                    console.log(f.id) //18
                    console.log(f.properties.STATE) //allways the same, this is good
                    var s = {
                        source: 'counties',
                        sourceLayer: 'us_counties-8xelrv',
                        id: f.id
                    map.setFeatureState(s, {
                        hover: true

Console gives the correct info (that is, ids are unique and state_code is the same for all filtered features when click on one county). Curiously Texas is one of the few working correctly, but, when zooming in/out, highlighting becomes a chaos.

I have also tried using uniqueFeatures_state as the object to iterate over, with no success.


querySourceFeatures only returns features loaded in the current map view, so when you zoom out, you'll have new features and not know about their IDs. You could watch for the moveend and sourcedata events and run querySourceFeatures again on each event.

  • Wanna solve this before going further. Even not zooming I get some completely wrong 'hovered' counties. Notice that console messages are all correct (it means that relatedFeatures is holding correct data, but is on the mapping that is incorrect. Oct 10 '19 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.