水平条形图退出方法不起作用

时间:2019-03-14 09:47:52

标签: javascript html d3.js

我有一个D3水平条形图,用于更新选择过滤器中的数据。图表首次呈现时,一切都会按预期进行。当过滤器选择任何下拉列表时,图表将按预期显示,但是当我再次选择“全部”选项时,y轴具有正确的域名,x轴重置为正确的比例。但是,会出现整个svg图表元素为灰色块的问题。如果将鼠标悬停在该栏上,则会选择该栏的正确大小,因此我认为旧数据无法正确退出,如下面的图片所示。

enter image description here 我以为我的bar.exit()调用正在删除元素而陷入困境,我对正在发生的事情的理解缺少关键点。我想我很亲密,但不确定我想念什么?

******更新*********

全选似乎会插入一个额外的“ rect”元素,该元素在首次运行时不存在。 enter image description here

看着控制台日志,我无法理解它是从哪里生成的,因为数组长度是3而不是4。

enter image description here

var topicData = [{
    "name": "Vehicle - Poor",
    "value": 5
  },
  {
    "name": "Problems - Unresolved",
    "value": 3
  },
  {
    "name": "Reliability - Poor",
    "value": 2
  }
]

var margin = {
  top: 10,
  right: 10,
  bottom: 100,
  left: 200
}
var width = 1000 - margin.left - margin.right,
  height = 700 - margin.top - margin.bottom;

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

var time = 0;
var data;

// Set the X Label
var xLabel = g.append("text")
  .attr("class", "x label")
  .attr("y", height + 50)
  .attr("x", width / 2)
  .attr("font-size", "15px")
  .attr("text-anchor", "middle")
  .text("Topic Count");

// Set the Y Label
var yLabel = g.append("text")
  .attr("class", "y axisLabel")
  .attr("transform", "rotate(-90)")
  .attr("y", -(120))
  .attr("x", -350)
  .attr("font-size", "15px")
  .attr("text-anchor", "middle")
  .text("Topic Names")

// Scales
var x = d3.scaleLinear().range([0, width]);

var y = d3.scaleBand()
  .range([height, 0]);
// X-axis
var xAxisCall = d3.axisBottom()
var xAxis = g.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")");

// Y-axis
var yAxisCall = d3.axisLeft()
var yAxis = g.append("g")
  .attr("class", "y axis");


//console.log(data);
formattedData = topicData;
update(formattedData)



$("#survey")
  .on("change", function() {
    update(formattedData);
  })


function step() {
  // At the end of our data, loop back
  time = (time < 214) ? time + 1 : 0
  update(formattedData);
}


function update(data) {
  console.log("I'm in the update function")




  var survey = $("#survey").val();
  var data = data.filter(function(d) {
    if (survey == "all") {
      return true;
    } else {
      return d.name == survey;
    }
  })

  console.log(data)

  // X Scale
  x.domain([0, d3.max(data, function(d) {
    return d.value;
  })]);
  y.domain(data.map(function(d) {
    return d.name;
  }));

  // Update axes
  xAxisCall.scale(x);
  xAxis.transition().call(xAxisCall);
  yAxisCall.scale(y);
  yAxis.transition().call(yAxisCall);

  // JOIN new data with old elements
  var bars = g.selectAll(".bars").data(data, function(d) {
    return d.name;
  });

  // EXIT old elements not present in new data.
  bars.exit()
    .attr("class", "exit")
    .remove();




  // ENTER new elements present in new data.
  bars.enter()
    .append("rect")
    .attr("width", function(d) {
      return x(d.value);
    }) // Width corresponds with the value from the data
    .attr("y", function(d) {
      return y(d.name);
    }) // Maps the name to the bar
    .attr("height", y.bandwidth())
    .attr("fill", "grey")
    .on("mouseover", function() {
      d3.select(this)
        .attr("fill", "blue");
    })
    .on("mouseout", function(d, i) {
      d3.select(this)
        .attr("fill", "grey");
    })
    .on('click', function click(element) {
      selection = element.name;
      url = "http://127.0.0.1:5000/table"
      window.location = url;
      window.localStorage.setItem("topic", selection)
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.min.js"></script>

<select id="survey" data-placeholder="Select..." class="chosen-select" style="width:350px;" tabindex="3">
  <option selected value="all">All</option>
  <option value="Vehicle - Poor">Vehicle - Poor</option>
  <option value="Problems - Unresolved">Problems - Unresolved</option>
  <option value="Reliability - Poor">Reliability - Poor</option>
</select>


<div class="col-md-12">
  <div id="graphic_two"></div>
</div>

1 个答案:

答案 0 :(得分:2)

接受的答案不正确(在更新D3 dataviz之前删除元素绝对不是惯用的方式),而且,它不能解释为什么退出选择不起作用

您的问题仅仅是您在更新选择中选择了一个课程...

var bars = g.selectAll(".bars")
    //etc...

...但是您永远不会在回车选择中设置该类。因此,只需:

bars = bars.enter()
    .append("rect")
    .attr("class", "bars")

此外,您还有其他问题:

  1. 您永远不会更改更新选择。请注意下面我的代码中的merge()
  2. 您正在更改乐队规模的范围。因此,每个条的宽度取决于条的数量。我感觉这不是您想要的。如果正确,请重构该部分代码。在下面的代码段中,我使用一个简单的paddingOuter数学来更改条形的宽度。

这是您所做的更改的代码:

var topicData = [{
    "name": "Vehicle - Poor",
    "value": 5
  },
  {
    "name": "Problems - Unresolved",
    "value": 3
  },
  {
    "name": "Reliability - Poor",
    "value": 2
  }
];

var margin = {
  top: 10,
  right: 10,
  bottom: 100,
  left: 200
}
var width = 1000 - margin.left - margin.right,
  height = 700 - margin.top - margin.bottom;

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

var time = 0;
var data;

// Set the X Label
var xLabel = g.append("text")
  .attr("class", "x label")
  .attr("y", height + 50)
  .attr("x", width / 2)
  .attr("font-size", "15px")
  .attr("text-anchor", "middle")
  .text("Topic Count");

// Set the Y Label
var yLabel = g.append("text")
  .attr("class", "y axisLabel")
  .attr("transform", "rotate(-90)")
  .attr("y", -(120))
  .attr("x", -350)
  .attr("font-size", "15px")
  .attr("text-anchor", "middle")
  .text("Topic Names")

// Scales
var x = d3.scaleLinear().range([0, width]);

var y = d3.scaleBand()
  .range([height, 0]);
// X-axis
var xAxisCall = d3.axisBottom()
var xAxis = g.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")");

// Y-axis
var yAxisCall = d3.axisLeft()
var yAxis = g.append("g")
  .attr("class", "y axis");

//console.log(data);
formattedData = topicData;
update(formattedData)

$("#survey")
  .on("change", function() {
    update(formattedData);
  })

function step() {
  // At the end of our data, loop back
  time = (time < 214) ? time + 1 : 0
  update(formattedData);
}

function update(data) {

  var survey = $("#survey").val();
  var data = data.filter(function(d) {
    if (survey == "all") {
      return true;
    } else {
      return d.name == survey;
    }
  })

  // X Scale
  x.domain([0, d3.max(data, function(d) {
    return d.value;
  })]);

  y.domain(data.map(function(d) {
      return d.name;
    }))
    .paddingOuter(1 / data.length);

  // Update axes
  xAxisCall.scale(x);
  xAxis.transition().call(xAxisCall);
  yAxisCall.scale(y);
  yAxis.transition().call(yAxisCall);

  // JOIN new data with old elements
  var bars = g.selectAll(".bars").data(data, function(d) {
    return d.name;
  });

  // EXIT old elements not present in new data.
  bars.exit()
    .attr("class", "exit")
    .remove();


  // ENTER new elements present in new data.
  bars = bars.enter()
    .append("rect")
    .attr("class", "bars")
    .merge(bars)
    .attr("width", function(d) {
      return x(d.value);
    }) // Width corresponds with the value from the data
    .attr("y", function(d) {
      return y(d.name);
    }) // Maps the name to the bar
    .attr("height", y.bandwidth())
    .attr("fill", "grey")
    .on("mouseover", function() {
      d3.select(this)
        .attr("fill", "blue");
    })
    .on("mouseout", function(d, i) {
      d3.select(this)
        .attr("fill", "grey");
    })
    .on('click', function click(element) {
      selection = element.name;
      url = "http://127.0.0.1:5000/table"
      window.location = url;
      window.localStorage.setItem("topic", selection)
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.min.js"></script>

<select id="survey" data-placeholder="Select..." class="chosen-select" style="width:350px;" tabindex="3">
  <option selected value="all">All</option>
  <option value="Vehicle - Poor">Vehicle - Poor</option>
  <option value="Problems - Unresolved">Problems - Unresolved</option>
  <option value="Reliability - Poor">Reliability - Poor</option>
</select>


<div class="col-md-12">
  <div id="graphic_two"></div>
</div>

PS:请勿混合使用jQuery和D3。这不仅不必要,而且有时有害。