Best way to show/hide CARTO layers using latest CARTO/DeckGL libraries in JS

269 Views Asked by At

In my hobby project I got about 15-20 map layers. Mostly polygons and sometimes icon layers.

Here is the link - heatmaps.com.au

I build it using older CartoDB libraries which are soon to be unsupported.

Now I am trying to recreate my project using the new CARTO v3 libraries and DeckGL. And can't get my head around how it works.

Here are key things I am trying to re-create:

  1. I would like to be able to show/hide layers upon click on menu items.

  2. When user hover over or click the map polygon - show tooltip with some stats.

  3. There are charts under the map. Clicking on a polygon triggers charts getting data for those polygons.

So far I learned how to create new layer with my data and show tooltips.

I am stuck with show/hide layers on menu clicks.

Would love to read some advise on how am I better to plan it all since I am just starting my migration from older CartoDB to a new platform.

I am only using JS, jquery. Don't know if I should learn React or some other frameworks.

Here is how I create layers:

    const deckgl = new deck.DeckGL({
      container: "map",
      map: maplibregl,
      mapStyle: deck.carto.BASEMAP.DARK_MATTER,

      initialViewState: {
        latitude: -33.85,
        longitude: 151.20,
        zoom: 12
      },
      controller: true,

      layers: [
        new deck.carto.CartoLayer({ // polygons
          id: 'heatmaps',
          connection: "carto_dw",
          type: deck.carto.MAP_TYPES.QUERY,
          data: "select geom, Postcode, Md_H22_num, Md_H22_txt, Ct_H22_num, Suburbs from carto-dw-ac-p76tk8ou.shared.2023FEB28_Postcode where Md_H22_num is not null",
          getFillColor: deck.carto.colorContinuous({
                          attr: "Md_H22_num",
                          domain: [0, 5000000],
                          colors: "PinkYl"
                        }),
          getLineColor:[255,255,255],
          lineWidthMinPixels: 1,
          pickable: true,
          getLineWidth: 2,
          opacity: 0.7
        }),
        new deck.carto.CartoLayer({ // text label
          id: 'points',
          connection: "carto_dw",
          type: deck.carto.MAP_TYPES.QUERY,
          data: 'select Postcode, Ct_H22_num, Md_H22_txt, Suburbs, st_centroid(geom) as geom from carto-dw-ac-p76tk8ou.shared.2023FEB28_Postcode where Md_H22_num is not null',
          pointType: 'text', 
          getText: f => f.properties.Md_H22_txt,
          textFontFamily: "sans-serif",
          textBackground: true,
          getTextBackgroundColor:  [0, 0, 0, 50],
          textBackgroundPadding: [2, 2],
          getTextSize: 12,
          getTextColor: [250,250,250],
          pickable: true,
        })
      ],
      getTooltip: ({ object }) => {
        if (!object) return false;
        return {
          className: `vptooltip`,
          html: `<div style='width:250px'>
          <span class='vptooltip-title'>Postcode:</span>            <p class='vptooltip-value'>${object.properties.Postcode}</p>
          <span class='vptooltip-title'>Suburbs:</span>             <p class='vptooltip-value'>${object.properties.Suburbs}</p>
          <span class='vptooltip-title'>Median House Price:</span>  <p class='vptooltip-value'>${object.properties.Md_H22_txt}</p>
          <span class='vptooltip-title'>Houses Sold:</span>         <p class='vptooltip-value'>${object.properties.Ct_H22_num}</p>
          </div>`,
        };
      }
    }); 

Tried follow the documentation for new CARTO v3 / DeckGL - but it's still too new and not many examples are available.

=== UPDATE

After googling and trying few things I seem to now know how to show/hide layers. Maybe not a perfect solution, but does the job for me.

So, I create a multiple objects - for example that one:

const layers = [
          new deck.carto.CartoLayer({ // polygons
          id: 'heatmaps',
          connection: "carto_dw",
          type: deck.carto.MAP_TYPES.QUERY,
          data: "select geom, Postcode, Md_H22_num, Md_H22_txt, Ct_H22_num, Suburbs from carto-dw-ac-p76tk8ou.shared.2023FEB28_Postcode where Md_H22_num is not null",
          getFillColor: deck.carto.colorContinuous({
                          attr: "Md_H22_num",
                          domain: [0, 5000000],
                          colors: "PinkYl"
                        }),
          getLineColor:[255,255,255],
          lineWidthMinPixels: 1,
          pickable: true,
          getLineWidth: 2,
          opacity: 0.3,
          visible: true
        })
];

, and then for example onclick some button call a JS function that does this:

deckgl.setProps({layers});
1

There are 1 best solutions below

0
Victor NSW On

=== UPDATE 2

Another solution found too. Here's full code:

<html>
  <head>

<!-- bootstrap 5 CSS -->
<link href="/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">

<!-- bootstrap & popper combo 5 JS -->
<script src="/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>




    <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script> 
    <script src="https://unpkg.com/@deck.gl/carto@latest/dist.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
    <link
      href="https://unpkg.com/[email protected]/dist/maplibre-gl.css"
      rel="stylesheet"
    />

    <style>
.vptooltip {
  color: #fff !important;
  font: 400 11px "Helvetica Neue",Helvetica,Arial !important;
  background: rgba(0,0,0,.75) !important;
  padding: 10px !important;
  border-radius: 3px !important;
}

.vptooltip-title {
color: #999;
margin: 0 0 1px;
font-weight: 600;
}

.vptooltip-value {
padding: 0 0 7px;
margin: 0 0 1px;
}

    </style>
  </head>

  <body style="margin: 0; padding: 0;">
  
  <div id="map" style="width: 100vw; height: 50vh;"></div>


Visibility: 
<input type="checkbox" id="showhide" checked onclick='render();'>



  </body>


  <script type="text/javascript">


    deck.carto.setDefaultCredentials({
      apiBaseUrl: "https://gcp-australia-southeast1.api.carto.com",
      accessToken:
        "ey_XXX"
    });


const layerVisibility = {visibility: document.getElementById('showhide').checked};


function render() {

    const layers = [
            new deck.carto.CartoLayer({ // polygons
              id: 'heatmaps',
              connection: "carto_dw",
              type: deck.carto.MAP_TYPES.QUERY,
              data: "select geom, Postcode, Md_H22_num, Md_H22_txt, Ct_H22_num, Suburbs from carto-dw-XXX",
              getFillColor: deck.carto.colorContinuous({
                              attr: "Md_H22_num",
                              domain: [0, 5000000],
                              colors: "PinkYl"
                            }),
              getLineColor:[255,255,255],
              lineWidthMinPixels: 1,
              pickable: true,
              getLineWidth: 2,
              opacity: 0.7,
              visible: layerVisibility.visibility
            })
      ];

      mydeckgl.setProps({layers});

      layerVisibility.visibility = !layerVisibility.visibility;
}



    const mydeckgl = new deck.DeckGL({
      container: "map",
      map: maplibregl,
      mapStyle: deck.carto.BASEMAP.DARK_MATTER,

      initialViewState: {
        latitude: -33.85,
        longitude: 151.20,
        zoom: 12
      },

      controller: true

    });

render();

  </script>
</html>