【问题标题】:Switch for making background map from Mapbox visible/invisible in D3用于在 D3 中使 Mapbox 中的背景地图可见/不可见的开关
【发布时间】:2015-03-09 08:10:08
【问题描述】:

我正在构建一个受http://chriszetter.com/blog/2014/06/15/building-a-voronoi-map-with-d3-and-leaflet/ 启发的 Voronoi 地图。我想选择关闭背景地图,因为数据的位置可能与我的所有用例都不相关。此外,如果可视化能够以这种方式离线工作,那就太好了。切换开关后,整个背景将是白色的。 Voronoi 重叠将是相同的。我怎么做?这是代码(zip 文件包含 csv 文件):https://www.dropbox.com/s/i8vtfh8mkxazfr0/voronoi-maps-master.zip?dl=0

编辑:当我试图将可视化分成两部分时,原始代码中有两个层变量。但是,该尝试没有成功,只使用了mapLayer。这在原始问题中可能不清楚。

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="base.css" rel="stylesheet" />
<link href='https://api.tiles.mapbox.com/mapbox.js/v1.6.3/mapbox.css' rel='stylesheet' />
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <div id='map'>
  </div>
  <div id='loading'>
  </div>
  <!-- <div id='selected'>
    <h1>...</h1>
  </div> -->
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min.js"></script>
  <script src="https://api.tiles.mapbox.com/mapbox.js/v1.6.3/mapbox.js"></script>
  <!-- <script src="/voronoi-map/lib/voronoi_map.js"></script> -->
  <script type="text/javascript" src="voronoi_map.js"></script>
  <script>
    map = L.mapbox.map('map', 'zetter.i73ka9hn') // <- dur ikke!
      .fitBounds([[59.355596 , -9.052734], [49.894634 , 3.515625]]);

    url = 'supermarkets.csv';
    initialSelection = d3.set(['Tesco', 'Sainsburys']);
    voronoiMap(map, url, initialSelection);
  </script>
</body>
</html>

voronoi_map.js

voronoiMap = function(map, url, initialSelections) {
  var pointTypes = d3.map(),
      points = [],
      lastSelectedPoint;

  var voronoi = d3.geom.voronoi()
      .x(function(d) { return d.x; })
      .y(function(d) { return d.y; });

  var selectPoint = function() {
    d3.selectAll('.selected').classed('selected', false);

    var cell = d3.select(this),
        point = cell.datum();

    lastSelectedPoint = point;
    cell.classed('selected', true);

    d3.select('#selected h1')
      .html('')
      .append('a')
        .text( /*point.name*/ "8 interactions from this cell")
        /* .attr('href', point.url)
        .attr('target', '_blank') */
  }

  var drawWithLoading = function(e){
    d3.select('#loading').classed('visible', true);
    if (e && e.type == 'viewreset') {
      d3.select('#overlay').remove();
    }
    setTimeout(function(){
      draw();
      d3.select('#loading').classed('visible', false);
    }, 0);
  }

  var draw = function() {
    d3.select('#overlay').remove();

    var bounds = map.getBounds(),
        topLeft = map.latLngToLayerPoint(bounds.getNorthWest()),
        bottomRight = map.latLngToLayerPoint(bounds.getSouthEast()),
        existing = d3.set(),
        drawLimit = bounds.pad(0.4);

    filteredPoints = points.filter(function(d) {
      var latlng = new L.LatLng(d.latitude, d.longitude);

      if (!drawLimit.contains(latlng)) { return false };

      var point = map.latLngToLayerPoint(latlng);

      key = point.toString();
      if (existing.has(key)) { return false };
      existing.add(key);

      d.x = point.x;
      d.y = point.y;
      return true;
    });

    voronoi(filteredPoints).forEach(function(d) { d.point.cell = d; });

    var svg = d3.select(map.getPanes().overlayPane).append("svg")
      .attr('id', 'overlay')
      .attr("class", "leaflet-zoom-hide")
      .style("width", map.getSize().x + 'px')
      .style("height", map.getSize().y + 'px')
      .style("margin-left", topLeft.x + "px")
      .style("margin-top", topLeft.y + "px");

    var g = svg.append("g")
      .attr("transform", "translate(" + (-topLeft.x) + "," + (-topLeft.y) + ")");

    var svgPoints = g.attr("class", "points")
      .selectAll("g")
        .data(filteredPoints)
      .enter().append("g")
        .attr("class", "point");

    var buildPathFromPoint = function(point) {
      return "M" + point.cell.join("L") + "Z";
    }


    svgPoints.append("path")
      .attr("class", "point-cell")
      .attr("d", buildPathFromPoint)
      //.style('fill', function(d) { return '#' + d.color } )
      .on('click', selectPoint)
      .classed("selected", function(d) { return lastSelectedPoint == d} );

    /* svgPoints.append("circle")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .style('fill', function(d) { return '#' + d.color } )
      .attr("r", 2); */
  }

/* function interactionGradient() {
    color = 

    if 
    return 
} */


  var mapLayer = {
    onAdd: function(map) {
      map.on('viewreset moveend', drawWithLoading);
      drawWithLoading();
    }
  };

  var voronoiLayer = {
    onAdd: function(map) {
      map.on('viewreset moveend', drawWithLoading);
      drawWithLoading();
    }
  };


  map.on('ready', function() {
    d3.csv(url, function(csv) {
      points = csv;
      points.forEach(function(point) {
        pointTypes.set(point.type, {type: point.type, color: point.color});
      })
      map.addLayer(mapLayer);
    })
  });
}

【问题讨论】:

    标签: javascript d3.js data-visualization mapbox


    【解决方案1】:

    您需要单独加载 tileLayer,以便创建对它的引用,然后您可以使用它来创建可以轻松启用/禁用图层的图层控件:

    L.mapbox.accessToken = 'pk.eyJ1IjoicGF1bC12ZXJob2V2ZW4iLCJhIjoiZ1BtMWhPSSJ9.wQGnLyl1DiuIQuS0U_PtiQ';
    
    // Create the tileLayer.
    var tileLayer = L.mapbox.tileLayer('examples.map-i86nkdio');
    
    var map = L.mapbox.map('mapbox', null, { // Do not add as parameter
        'center': [0, 0],
        'zoom': 1,
        // Add here so it still gets added to the map initially
        // You could skip this so it won't be added and you can
        // turn it on via the layercontrol
        'layers': [tileLayer] 
    });
    
    // Create layer control
    var layerControl = L.control.layers(null, {
        'Tilelayer': tileLayer // Add tile layer to overlays
    }).addTo(map);
    

    这是一个关于 Plunker 的工作示例:http://plnkr.co/edit/5re3o6qnyCwAqXNYXrkP?p=preview

    L.mapbox.tileLayer 参考:https://www.mapbox.com/mapbox.js/api/v2.1.5/l-mapbox-tilelayer/

    L.control.layers 参考:http://leafletjs.com/reference.html#control-layers

    因为 cmets 而编辑:

    您已经在使用单独的图层,tilelayer(背景)在地图初始化L.mapbox.map('map', 'zetter.i73ka9hn') 时添加,实际上调用:L.mapbox.tileLayer('zetter.i73ka9hn').addTo(map)。您需要这样做,因为您需要对该图层的引用,以便您可以将其添加到L.control.layers,如上所示。您的 voronoi 层被添加到地图的 ready 处理程序的 voronoiMap 方法中:map.addLayer(mapLayer);

    因此,您可以看到它们已经分开。现在,如果您还希望能够在图层控件中切换 voronoi 图层,则需要将其添加到图层控件中:

    map.on('ready', function() {
        d3.csv(url, function(csv) {
            points = csv;
            points.forEach(function(point) {
                pointTypes.set(point.type, {
                    type: point.type,
                    color: point.color
                });
            });
            map.addLayer(mapLayer);
            layerControl.addOverlay(mapLayer, 'Voronoi'); // Here
        })
    });
    

    但在您的情况下,这本身还不够,因为您的层没有 ILayer 接口规定的onRemove 方法:

    http://leafletjs.com/reference.html#ilayer

    现在,如果我们像这样向您的层添加onRemove 方法:

    var mapLayer = {
        onAdd: function(map) {
            map.on('viewreset moveend', drawWithLoading);
            drawWithLoading();
        },
        onRemove: function (map) {
            d3.select('#overlay').remove();
        }
    };
    

    它有效:http://plnkr.co/edit/3z3pCAo0gGuA7xqnqiqb?p=preview(注意我已经注释掉了ready 处理程序,因为地图在函数调用之前就准备好了,所以它不会触发并更改了一些颜色以使事情更清晰。)希望这会有所帮助.

    【讨论】:

    • 看起来不错!我一直在尝试将当前代码(特别是在“绘制”函数中)分成两个单独的层,这样我就可以在没有背景图的情况下绘制 voronoi,但没有任何运气,因为它们似乎过于交织在一起。您将如何分隔 voronoi_map.js 中的两层?
    • 很高兴你喜欢它 :) 但是你现在所问的完全脱离了当前的背景,而且 cmets 并不是用来提出新问题的,而且真的不适合回答。如果它有助于解决您的问题,为什么不接受这个当前的答案,以便其他有类似问题的人也可以找到解决方案,请参阅:stackoverflow.com/help/someone-answers 并在一个新问题中提出这个问题,以便其他人也可以帮助找到解决方案?这样您就可以帮助创建和保持 SO 成为一个出色的问答网站。
    • 如何脱离当前语境?我的问题是:“切换开关后,整个背景都是白色的。Voronoi 重叠将是相同的。”使用图层控件,我可以关闭图层,但这会禁用 both 背景和 Voronoi 叠加层,因为它们在代码中作为一层实现。这只是完全关闭了可视化。为了让它工作,可视化需要分成两层。总结一下:我的评论描述了我一直在尝试扩展您的答案以解决问题:)
    • 我完全没有按照您的要求进行操作。在您的代码中,您将在 index.html 中单独添加切片图层,而 voronio 将在 voronoiMap 方法中单独添加。他们是分开的?我一定是真的忽略了这里的某些东西,或者完全误解了你想要的东西。
    • 我已经编辑了我的答案并添加了一个示例,以便您可以清楚地看到您已经在使用两个单独的层。
    猜你喜欢
    • 2020-04-24
    • 2013-08-18
    • 1970-01-01
    • 2016-07-28
    • 2012-03-31
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    相关资源
    最近更新 更多