如何过滤元素并隐藏其他元素?

时间:2018-03-27 16:19:59

标签: d3.js filter

我修改了一些d3过滤块,意图按年过滤(理想情况下是通过滑块而不是每年都有一个按钮),但遇到了两个问题:

  1. 在调用filter()和exit()时,remove()没有任何反应
  2. 这些年我怎么能添加滑块或自动播放?我查看了一些例子,但对于初学者来说它们有点复杂。
  3.     <!DOCTYPE html>
        <html lang="en">
        	<head>
              <script src="https://d3js.org/d3.v4.min.js"></script>
        		<meta charset="utf-8">
        		<title>D3: Loading data from a CSV file</title>
          </head>
        	<body>
            <p class="s12"> select 2012 </p>
            <p class="s16"> select 2016 </p>
        		<script type="text/javascript">
        
              var margin = {top: 20, right: 20, bottom: 30, left: 40},
            		w = 600 - margin.left - margin.right,
            		h = 300 - margin.top - margin.bottom;
              var padding = 40;
              
              var data = [{
              "Food": "Apples",
              "Deliciousness": 9,
              "year": 2010
            }, {
              "Food": "Green Beans",
              "Deliciousness": 5,
              "year": 2012
            }, {
              "Food": "Egg Salad Sandwich",
              "Deliciousness": 4,
              "year": 2016
            }, {
              "Food": "Cookies",
              "Deliciousness": 10,
              "year": 2018
            } ];
        
                // format the data
                data.forEach(function(d) {
                  d.Deliciousness = +d.Deliciousness;
                });
                
                
              var svg = d3.select("body")
        						.append("svg")
        						.attr("width", w + margin.left + margin.right)
        						.attr("height", h + margin.top + margin.bottom)
              			.append("g")
              			.attr("transform", "translate(" + margin.left+"," +
                         margin.top+")");
                
              var xScale = d3.scaleBand()
              	.domain(d=>d.Food)
              	.range([margin.left,w+margin.left])
              	.paddingInner(0.2);
             xScale.domain(data.map(function(d) { return d.Food; }));
        
                
              var xAxis = d3.axisBottom()
              	.scale(xScale)
              	.ticks(5);
              
              var yScale = d3.scaleLinear()
              	.domain([0, d3.max(data, d=>d.Deliciousness)])
              	.rangeRound([h+margin.top,margin.top]);
                
              var yAxis = d3.axisLeft()
              	.scale(yScale)
              	.ticks(5);
              
              svg.selectAll('rect')
                .data(data)
                .enter()
                .append('rect')
                .attr('x',(d,i) => margin.left + i*w/data.length)
                .attr('y',d=>yScale(d.Deliciousness))
                .attr('width', xScale.bandwidth())
                .attr('height',d =>h-yScale(d.Deliciousness))
                .attr('fill',function(d){
                  if (d===30) return "red";
                  return "rgb(0,0,"+d.Deliciousness*10+")" ;});
                
              
              svg.append("g")
              	.attr("class", "axis")
        	   		.attr("transform", "translate(" + padding + ",0)")
              	.call(yAxis);
                
        			svg.append("g")
              	.attr("class", "axis")
        	   		.attr("transform", "translate(0," + h + ")")
              	.call(xAxis);
               
              d3.select(".s12")
      				.on("click", function() {
          svg.selectAll("rect")
          .filter(function(d) {
            return d.year !== 2012;
          })
          .remove();
            
           d3.select(".s16")
        			.on("click", function() {
           svg.selectAll("rect")
            .filter(function(d) {
              return d.year !== 2016;
            })
            .remove();  
             });
                
            
        		</script>
        	</body>
        </html>

    代码已更新

1 个答案:

答案 0 :(得分:1)

首先,修复comments section中解释的类问题。

这里你的问题是这个块的逻辑:

svg.selectAll("rect")
    .data(data.filter(function(d) {
        return d.year == 2012;
    }))
    .exit().remove();

这没有多大意义:你正在做的是按年(2012)过滤数据数组,这将只返回 1 对象。然后,您选择所有矩形,仅使用一个对象绑定一个新数据数组(这将保留所有其他矩形,没有任何数据),然后在退出选择上调用remove。那不对。

由于您没有数据,只需过滤选择:

svg.selectAll("rect")
    .filter(function(d) {
        return d.year !== 2012;
    })
    .remove();

这样,您只需删除不代表2012的矩形。

这是更新的代码:

var margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 40
  },
  w = 600 - margin.left - margin.right,
  h = 300 - margin.top - margin.bottom;
var padding = 40;

var data = [{
  "Food": "Apples",
  "Deliciousness": 9,
  "year": 2010
}, {
  "Food": "Green Beans",
  "Deliciousness": 5,
  "year": 2012
}, {
  "Food": "Egg Salad Sandwich",
  "Deliciousness": 4,
  "year": 2016
}, {
  "Food": "Cookies",
  "Deliciousness": 10,
  "year": 2018
}];

// format the data
data.forEach(function(d) {
  d.Deliciousness = +d.Deliciousness;
});


var svg = d3.select("body")
  .append("svg")
  .attr("width", w + margin.left + margin.right)
  .attr("height", h + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," +
    margin.top + ")");

var xScale = d3.scaleBand()
  .domain(d => d.Food)
  .range([margin.left, w + margin.left])
  .paddingInner(0.2);
xScale.domain(data.map(function(d) {
  return d.Food;
}));


var xAxis = d3.axisBottom()
  .scale(xScale)
  .ticks(5);

var yScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.Deliciousness)])
  .rangeRound([h + margin.top, margin.top]);

var yAxis = d3.axisLeft()
  .scale(yScale)
  .ticks(5);

svg.selectAll('rect')
  .data(data)
  .enter()
  .append('rect')
  .attr('x', (d, i) => margin.left + i * w / data.length)
  .attr('y', d => yScale(d.Deliciousness))
  .attr('width', xScale.bandwidth())
  .attr('height', d => h - yScale(d.Deliciousness))
  .attr('fill', function(d) {
    if (d === 30) return "red";
    return "rgb(0,0," + d.Deliciousness * 10 + ")";
  });


svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(" + padding + ",0)")
  .call(yAxis);

svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(0," + h + ")")
  .call(xAxis);

d3.select(".s12")
  .on("click", function() {
    svg.selectAll("rect")
      .filter(function(d) {
        return d.year !== 2012;
      })
      .remove();
  });
<script src="https://d3js.org/d3.v4.min.js"></script>
<p class="s12"> select 2012 </p>
<p class="s16"> select 2016 </p>

相关问题