在D3中切换从Mapbox可见/不可见的背景图

时间:2015-03-09 08:10:09

标签: javascript d3.js data-visualization mapbox

我正在构建一个受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);
    })
  });
}

1 个答案:

答案 0 :(得分: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

因为评论而编辑:

您已经在使用单独的图层,在地图初始化L.mapbox.map('map', 'zetter.i73ka9hn')上添加了图块层(背景),实际上调用了L.mapbox.tileLayer('zetter.i73ka9hn').addTo(map)。您需要这样做,因为您需要对图层的引用,以便您可以将其添加到L.control.layers,如上所示。您的voronoi图层将添加到地图的voronoiMap处理程序中的ready方法中: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处理程序,因为地图在函数调用之前就已准备就绪,因此它不会触发并更改某些颜色事情更清楚。)希望这会有所帮助。