【问题标题】:CartoDB multiple layer toggleCartoDB 多层切换
【发布时间】:2025-12-10 13:45:01
【问题描述】:

我正在尝试制作一张地图,您可以在其中切换三个不同的图层,并让所有人都能看到相同的图例。我目前正在关注此文档: http://docs.cartodb.com/tutorials/toggle_map_view.html

我在 CartoDB 中的地图具有三个独立的图层(包含 2013、2014 和 2015 年的三个数据集)。

我正在尝试制作一个类似于文档中的切换图。到目前为止,这是我所做的:

<html>
<head>
  <link rel="stylesheet" href="http://libs.cartocdn.com/cartodb.js/v3/3.11/themes/css/cartodb.css" />
  <script src="http://libs.cartocdn.com/cartodb.js/v3/3.11/cartodb.js"></script>
  <style>
    html, body {width:100%; height:100%; padding: 0; margin: 0;}
    #map { width: 100%; height:100%; background: black;}
    #menu { position: absolute; top: 5px; right: 10px; width: 400px; height:60px; background: transparent; z-index:10;}
    #menu a { 
      margin: 15px 10px 0 0;
      float: right;
      vertical-align: baseline;
      width: 70px;
      padding: 10px;
      text-align: center;
      font: bold 11px "Helvetica",Arial;
      line-height: normal;
      color: #555;
      border-radius: 4px;
      border: 1px solid #777777;
      background: #ffffff;
      text-decoration: none;
      cursor: pointer;
    }
    #menu a.selected,
    #menu a:hover { 
      color: #F84F40;
    }
  </style>

  <script>
var map;
    function init(){
  // initiate leaflet map
  map = new L.Map('map', { 
    center: [20,-20],
    zoom: 3
  })

  L.tileLayer('https://dnv9my2eseobd.cloudfront.net/v3/cartodb.map-4xtxp73f/{z}/{x}/{y}.png', {
    attribution: 'Mapbox <a href="http://mapbox.com/about/maps" target="_blank">Terms &amp; Feedback</a>'
  }).addTo(map);

  var layerUrl = 'http://heathermartino.cartodb.com/api/v2/viz/415f8ed2-d493-11e4-b129-0e018d66dc29/viz.json';

  var sublayers = [];

  cartodb.createLayer(map, layerUrl)
  .addTo(map)
  .on('done', function(layer) {
    // change the query for the first layer
    var subLayerOptions = {
      sql: "SELECT * FROM gdp_2014",
      cartocss: "#gdp_2014{marker-fill: #F84F40; marker-width: 8; marker-line-color: white; marker-line-width: 2; marker-clip: false; marker-gdp_2015ow-overlap: true;}"
    }

    var sublayer = layer.getSubLayer(0);

    sublayer.set(subLayerOptions);

    sublayers.push(sublayer);
  }).on('error', function() {
    //log the error
  });

  //we define the queries that will be performed when we click on the buttons, by modifying the SQL of our layer
  var LayerActions = {
    GDP_2015: function(){
      sublayers[0].setSQL("SELECT * FROM gdp_2015");
      return true;
    },
    GDP_2014: function(){
      sublayers[0].setSQL("SELECT * FROM gdp_2014");
      return true;
    },
    GDP_2013: function() {
      sublayers[0].set({
        sql: "SELECT * FROM gdp_2013 WHERE cartodb_georef_status = true",
        //as it is said, you can also add some CartoCSS code to make your points look like you want for the different queries
       // cartocss: "#ne_10m_populated_places_simple{ marker-fill: black; }"
      });
      return true;
    }
  }

  $('.button').click(function() {
    $('.button').removeClass('selected');
    $(this).addClass('selected');
    //this gets the id of the different buttons and cgdp_2015s to LayerActions which responds according to the selected id
    LayerActions[$(this).attr('id')]();
  });


    L.tileLayer('https://dnv9my2eseobd.cloudfront.net/v3/cartodb.map-4xtxp73f/{z}/{x}/{y}.png', {
      attribution: 'Mapbox <a href="http://mapbox.com/about/maps" target="_blank">Terms &amp; Feedback</a>'
    }).addTo(map);
  }
  </script>
</head>

<body onload="init()">
  <div id='map'></div>
  <div id='menu'>
    <a href="#gdp_2013" id="gdp_2013" class="button gdp_2013">2013</a> 
    <a href="#gdp_2014" id="gdp_2014" class="button gdp_2014">2014</a> 
    <a href="#gdp_2015" id="gdp_2015" class="button gdp_2015">2015</a>
  </div>
</body>
</html>

现在,当您单击 2013、2014 和 2015 的不同按钮时,什么也没有发生。作为参考,我在carto 中的地图是http://cdb.io/1Bzm2tD。有任何想法吗?提前致谢!

【问题讨论】:

  • 链接中的 id 是小写的,但您的操作函数的哈希键是大写的 (GDP_2015)。可以像小写键一样简单吗?

标签: toggle layer cartodb


【解决方案1】:

你有层次。无需再次运行 SQL。这应该可以。

<html>

<head>
    <link rel="stylesheet" href="http://libs.cartocdn.com/cartodb.js/v3/3.11/themes/css/cartodb.css" />
    <script src="http://libs.cartocdn.com/cartodb.js/v3/3.11/cartodb.js"></script>
    <style>
    html,
    body {
        width: 100%;
        height: 100%;
        padding: 0;
        margin: 0;
    }

    #map {
        width: 100%;
        height: 100%;
        background: black;
    }

    #menu {
        position: absolute;
        top: 5px;
        right: 10px;
        width: 400px;
        height: 60px;
        background: transparent;
        z-index: 10;
    }

    #menu a {
        margin: 15px 10px 0 0;
        float: right;
        vertical-align: baseline;
        width: 70px;
        padding: 10px;
        text-align: center;
        font: bold 11px "Helvetica", Arial;
        line-height: normal;
        color: #555;
        border-radius: 4px;
        border: 1px solid #777777;
        background: #ffffff;
        text-decoration: none;
        cursor: pointer;
    }

    #menu a.selected,
    #menu a:hover {
        color: #F84F40;
    }

    .cartodb-layer-selector-box,
    .cartodb-searchbox,
    .cartodb-share {
        display: none !important;
    }
    </style>
    <script>
    var layer;


    function init() {
        var url = 'http://heathermartino.cartodb.com/api/v2/viz/415f8ed2-d493-11e4-b129-0e018d66dc29/viz.json';
        var visualizacion = cartodb.createVis("map", url)
            .done(function(vis, layers) {
                layer = layers[1];
            });
    }

    function showLayer(layerToShow) {

        //turn off all layers
        layer.getSubLayers().forEach(function(i) {
            i.hide()
        });

        switch (layerToShow.id) {
            case "gdp_2013":
                layer.getSubLayer(0).show();
                break;
            case "gdp_2014":
                layer.getSubLayer(1).show();
                break;
            case "gdp_2015":
                layer.getSubLayer(2).show();
                break;
        }

        return true;
    }
    </script>
</head>

<body onload="init()">
    <div id='map'></div>
    <div id='menu'>
        <a href="#gdp_2013" id="gdp_2013" class="button gdp_2013" onclick="showLayer(this);">2013</a>
        <a href="#gdp_2014" id="gdp_2014" class="button gdp_2014" onclick="showLayer(this);">2014</a>
        <a href="#gdp_2015" id="gdp_2015" class="button gdp_2015" onclick="showLayer(this)">2015</a>
    </div>
</body>

</html>

【讨论】:

    【解决方案2】:

    我已经创建了类似的东西 - 看看这是否有帮助。对我来说,诀窍是让子层用 for 循环分隔,然后创建按钮以作用于每个子层。

     function loadPosition(position) {
    
                    lati = position.coords.latitude;
                    longi = position.coords.longitude;
                    map = L.map('map', {zoomControl: false}).setView([lati, longi], 15);
    
                    L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {maxZoom: 19,}).addTo(map);
    
                    L.control.scale({position: 'bottomright'}).addTo(map);
    
    
                    /*CARTODB LAYERS*/
                    var layerSource = {
                        user_name: 'YOUR USER NAME',
                        type: 'cartodb',
                        cartodb_logo: false,
                        sublayers: [{
                            sql: "SELECT * FROM winston_survey_tool WHERE point_class LIKE 'Orientation point'",
                            cartocss: '#winston_survey_tool{marker-fill:#D94C38;marker-opacity:1;line-color:#FFF;line-width:1;line-opacity:1;marker-allow-overlap:true; [zoom >= 15] {marker-width: 15} [zoom >= 19] {marker-width: 20}}'
                            },
                            {
                            sql: "SELECT * FROM winston_survey_tool WHERE point_class LIKE 'Survey point'",
                            cartocss: '#winston_survey_tool{marker-fill:#E0D03D;marker-opacity:1;line-color:#FFF;line-width:1;line-opacity:1;marker-allow-overlap:true;  [zoom >= 15] {marker-width: 15} [zoom >= 19] {marker-width: 20}}'
                            }]
                        };
    
                    // STORE SUBLAYERS
                    var sublayers = [];
    
    
                // ADD LAYER TO MAP
                cartodb.createLayer(map,layerSource)
                .addTo(map)
                .done(function(layer) {
    
                    // SEPARATE THE SUBLAYERS
                    for (i = 0; i < layer.getSubLayerCount(); i++) {
                        sublayers[i] = layer.getSubLayer(i);
                        sublayers[i].hide();
                    };
    
    
                    // BUTTONS
                    $('#orientationCheck').click(function () {
    
                        orientationValue = $("#orientationCheck").val();
    
                        var query = "SELECT * FROM winston_survey_tool WHERE date LIKE'%";    
                        yearSelectVal = $("#yearSelect").val();
    
                        query = query + yearSelectVal + "' AND point_class LIKE 'Orientation point'";
    
                        sublayers[0] = sublayers[0].setSQL(query);
    
                        if(orientationValue=="ON"){
                            sublayers[0].hide();
                            $('#orientationCheck').val("OFF");
                            $("#orientationCheck").addClass("off");
                            }
                        else{
                            sublayers[0].show();
                            $('#orientationCheck').val("ON");
                            $("#orientationCheck").removeClass("off");
                            };
                        });
    
    
    
                    $('#surveyCheck').click(function () {
    
                        surveyValue = $("#surveyCheck").val();
    
                        var query = "SELECT * FROM winston_survey_tool WHERE date LIKE'%";    
                        yearSelectVal = $("#yearSelect").val();
    
                        query = query + yearSelectVal + "' AND point_class LIKE 'Survey point'";
    
                        sublayers[1] = sublayers[1].setSQL(query);
    
                        if(surveyValue=="ON"){
                            sublayers[1].hide();
                            $('#surveyCheck').val("OFF");
                            $("#surveyCheck").addClass("off");
                            }
                        else{
                            sublayers[1].show();
                            $('#surveyCheck').val("ON");
                            $("#surveyCheck").removeClass("off");
                            };           
                        });
                    });
    

    【讨论】:

    • 这里的主要内容是我为每个 SQL 查询创建了一个单独的子层,有效地将原来的一层点一分为二(方向和调查)。