D3.js Opacity filters partially working

安稳与你 提交于 2019-12-25 08:20:23

问题


I have a solid d3.js graph that works well for the most part. There are 4 node types:

     Agent,Customer,Phone,ID_Card

There are checkboxes that handle the opacity of the nodes and links. If Agent and Customer are checked then the 2 nodes and all possible links between them are opaque. And rest of the graph has

 opacity(0)

Also, there is a Search feature , which lets the user search through the graph with the below node attribute

    d.id

A node for which the input ID matches , will stay opaque and the rest of the graph will fade out for a few seconds

Below is the HTML

          <label>
    <input type="checkbox" name="checkb" value="Agent"> type=Agent</label>
  <br />
  <label>
    <input type="checkbox" name="checkb" value="Customer"> type=Customer</label>
  <br />
  <label>
    <input type="checkbox" name="checkb" value="Phone"> type=Phone</label>
  <br />
  <label>
    <input type="checkbox" name="checkb" value="ID_Card"> type=ID_Card</label>
  <br />

 <input type="text" id="node" />
  <button id="search">
    Search_Node
  </button>
</div>

Below is the javascript code that ensures that all the filters work well together in tandem.

For instance , if Customer and Phone are checked and if the Search feature is applied to search either a Customer or a Phone , the remaining two nodes that were unchecked will still remain at

   opacity(0)

And the search will be applied only to the sub graph.

  d3.selectAll("input[name=checkb]").on("change", function() {
    function getCheckedBoxes(chkboxName) {
      var checkboxes = document.getElementsByName(chkboxName);
      var checkboxesChecked = [];
      for (var i = 0; i < checkboxes.length; i++) {
        if (checkboxes[i].checked) {
          checkboxesChecked.push(checkboxes[i].defaultValue);
        }

      }
      return checkboxesChecked.length > 0 ? checkboxesChecked : " ";
    }

    var checkedBoxes = getCheckedBoxes("checkb");

    node.style("opacity", 1);
    link.style("opacity", 1);

    node.filter(function(d) {
        return checkedBoxes.indexOf(d.type) === -1;
      })
      .style("opacity", "0");

    link.filter(function(d) {
        return checkedBoxes.indexOf(d.source.type) === -1 ||
          checkedBoxes.indexOf(d.target.type) === -1;
      })
      .style("opacity", "0");

    link.filter(function(d) {
        return checkedBoxes.indexOf(d.source.type) > -1 &&
          checkedBoxes.indexOf(d.target.type) > -1;
      })
      .style("opacity", "1");


  });

  // get the checkboxes
  var typeAgentChk = document.querySelectorAll('input[value="Agent"]')[0];
  var typeCustomerChk = document.querySelectorAll('input[value="Customer"]')[0];
  var typePhoneChk = document.querySelectorAll('input[value="Phone"]')[0];
  var typeIDCardChk = document.querySelectorAll('input[value="ID_Card"]')[0];

  var checkBoxes = [typeAgentChk, typeCustomerChk, typePhoneChk, typeIDCardChk];
  var nodeTypes = ["Agent", "Customer", "Phone", "ID_Card"];


  var filterByCheckBox = function(el) {
    if (el.checked) {
      // filter
      filterBy("type", el.value, false);
    } else {
      removeFilterFor("type", el.value);
    }
  }

  var removeFilterFor = function(attribute, value) {
    var node = svg.selectAll(".node");
    var link = svg.selectAll(".link");
    var selected = node.filter(function(d) { // filter by attribute/value
        return d[attribute] == value;
      })
      .style("opacity", 0)
      .each(function(d) {
        var index = filtered.indexOf(d.id);
        if (index > -1) {
          filtered.splice(index, 1);
        }
      });
  }
  var filterBy = function(attribute, value, restoreAll, highlightSelected) {
    // get nodes and links - could be moved outside for efficiency
    var node = svg.selectAll(".node");
    var link = svg.selectAll(".link");
    if (value == "none" || value == null) { // do we need this?
      node.style("stroke", "white").style("stroke-width", "1");
    } else {
      var selected = node.filter(function(d) { // filter by attribute/value
        return d[attribute] == value;
      });

      // get any nodes we have filtered before
      var alreadyFiltered = node.filter(function(d) {
        return filtered.indexOf(d.id) > -1;
      })
      var alreadyFilteredLinks = link.filter(function(d) {
        return filtered.indexOf(d.source.id) > -1 && filtered.indexOf(d.target.id) > -1;
      })
      // hide all
      node.style("opacity", 0);
      link.style("opacity", 0);
      if (highlightSelected) {

        svg.selectAll(".node, .link").transition()
          .duration(1000)
          .style("opacity", 0);
      }
      selected.style("opacity", 1)
        .each(function(d) { // save the id's in the filtered list
          if (filtered.indexOf(d.id) == -1) {
            filtered.push(d.id);
          }
        });

      // but the already filtered and the currently selected
      alreadyFiltered.transition()
        .duration(3000)
        .style("opacity", 1);
      alreadyFilteredLinks.transition()
        .duration(3000)
        .style("opacity", 1);



      if (restoreAll) { // restore all 
        filtered = [];
        svg.selectAll(".node, .link").transition()
          .duration(5000)
          .style("opacity", 1);
      }
    }
  }



for (let i = 0; i < checkBoxes.length; i++) {
    checkBoxes[i].checked = true;
    //filterByCheckBox(checkBoxes[i]); // add all ids in filtered
    checkBoxes[i].addEventListener("click", function() {
      filterByCheckBox(checkBoxes[i])
    });
  }

  searchBtn.addEventListener("click", function() {
    // get value to filter with
    var selectedVal = document.getElementById('node').value;
    if (nodeTypes.indexOf(selectedVal) > -1) { // we filter by type
      filterBy("type", selectedVal, false);
    } else {
      console.log("filterBy", "id", selectedVal)
      filterBy("id", selectedVal, false, true);
    }
  });

This seems to be working as expected for the most part. The unchecking of checkboxes works fine and seems to make the unchecked nodes at

 opacity(0)

But when those nodes are checked back again , it does not seem to work well.

For instance, if Customer and Phone remained check and the other two remain unchecked, only Customer and Phone are visible. But if the Agent node is re-checked again , even ID_Card node becomes visible though it is still unchecked.

This holds true during checking back of any node. Even the unchecked node becomes visible.

Below is the fiddle

来源:https://stackoverflow.com/questions/41558545/d3-js-opacity-filters-partially-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!