我如何处理数据过滤上的一个按钮点击D3.js

How can I handle data filtering on a button click on D3.js?

本文关键字:按钮 一个 js D3 何处理 处理 数据 过滤      更新时间:2023-09-26

我有一个D3.js图表我正在工作,它工作得很好。然而,我试图在我的主html上添加按钮来处理数据过滤。这些按钮由外部操作。我似乎想不出最好的方法来处理这个功能,使它工作。任何帮助都将非常感激。这里是源代码。

对于"Popular"的单击事件,我希望显示值大于5的节点。在奇迹。json,我有一个流行属性值。当我点击All时,它应该会显示所有的数据。

任何输入将非常感谢。

index . html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Marvel Characters | Force layout with images</title>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <style>
      @import url(http://fonts.googleapis.com/css?family=Source+Code+Pro:400,600);
      body {font-family: "Source Code Pro", Consolas, monaco, monospace; line-height: 160%; font-size: 16px;  margin: 0; }
      path.link {
        fill: none;
        stroke-width: 2px;
      }
      .node:not(:hover) .nodetext {
        display: none;
      }
      h1 { font-size: 36px; margin: 10px 0; text-transform: uppercase; font-weight: normal;}
      h2, h3 { font-size: 18px; margin: 5px 0 ; font-weight: normal;}
      header {padding: 20px; position: absolute; top: 0; left: 0;}
      a:link { color: #EE3124; text-decoration: none;}
      a:visited { color: #EE3124; }
      a:hover { color: #A4CD39; text-decoration: underline;}
      a:active { color: #EE3124; }
    </style>
</head>

<body>
    <header>
<!-- D3 BUTTONS -->
  <div class="btn-group" role="group">
    <button type="button" class="btn btn-default button1 active">All</button>
    <button type="button" class="btn btn-default button3">Popular</button>
  </div>
      <h1>Marvel Characters</h1>
      <h2>Click to view their identity</h2>
      <h3>And link to their web page!</h3>
    </header>
    <!-- container for force layout visualisation  -->
    <section id="vis"></section> 
<script>
// some colour variables
  var tcBlack = "#130C0E";
// rest of vars
var w = 960,
    h = 800,
    maxNodeSize = 50,
    x_browser = 20,
    y_browser = 25,
    root;
var vis;
var force = d3.layout.force(); 
vis = d3.select("#vis").append("svg").attr("width", w).attr("height", h);
d3.json("marvel.json", function(json) {
  root = json;
  root.fixed = true;
  root.x = w / 2;
  root.y = h / 4;

        // Build the path
  var defs = vis.insert("svg:defs")
      .data(["end"]);

  defs.enter().append("svg:path")
      .attr("d", "M0,-5L10,0L0,5");
     update();
});

/**
 *   
 */
function update() {
  var nodes = flatten(root),
      links = d3.layout.tree().links(nodes);
  // Restart the force layout.
  force.nodes(nodes)
        .links(links)
        .gravity(0.05)
    .charge(-1500)
    .linkDistance(100)
    .friction(0.5)
    .linkStrength(function(l, i) {return 1; })
    .size([w, h])
    .on("tick", tick)
        .start();
   var path = vis.selectAll("path.link")
      .data(links, function(d) { return d.target.id; });
    path.enter().insert("svg:path")
      .attr("class", "link")
      // .attr("marker-end", "url(#end)")
      .style("stroke", "#eee");

  // Exit any old paths.
  path.exit().remove();

  // Update the nodes…
  var node = vis.selectAll("g.node")
      .data(nodes, function(d) { return d.id; });

  // Enter any new nodes.
  var nodeEnter = node.enter().append("svg:g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .on("click", click)
      .call(force.drag);
  // Append a circle
  nodeEnter.append("svg:circle")
      .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
      .style("fill", "#eee");

  // Append images
  var images = nodeEnter.append("svg:image")
        .attr("xlink:href",  function(d) { return d.img;})
        .attr("x", function(d) { return -25;})
        .attr("y", function(d) { return -25;})
        .attr("height", 50)
        .attr("width", 50);
  // make the image grow a little on mouse over and add the text details on click
  var setEvents = images
          // Append hero text
          .on( 'click', function (d) {
              d3.select("h1").html(d.hero); 
              d3.select("h2").html(d.name); 
              d3.select("h3").html ("Take me to " + "<a href='" + d.link + "' >"  + d.hero + " web page ⇢"+ "</a>" ); 
           })
          .on( 'mouseenter', function() {
            // select element in current context
            d3.select( this )
              .transition()
              .attr("x", function(d) { return -60;})
              .attr("y", function(d) { return -60;})
              .attr("height", 100)
              .attr("width", 100);
          })
          // set back
          .on( 'mouseleave', function() {
            d3.select( this )
              .transition()
              .attr("x", function(d) { return -25;})
              .attr("y", function(d) { return -25;})
              .attr("height", 50)
              .attr("width", 50);
          });
  // Append hero name on roll over next to the node as well
  nodeEnter.append("text")
      .attr("class", "nodetext")
      .attr("x", x_browser)
      .attr("y", y_browser +15)
      .attr("fill", tcBlack)
      .text(function(d) { return d.hero; });

  // Exit any old nodes.
  node.exit().remove();

  // Re-select for update.
  path = vis.selectAll("path.link");
  node = vis.selectAll("g.node");
function tick() {

    path.attr("d", function(d) {
     var dx = d.target.x - d.source.x,
           dy = d.target.y - d.source.y,
           dr = Math.sqrt(dx * dx + dy * dy);
           return   "M" + d.source.x + "," 
            + d.source.y 
            + "A" + dr + "," 
            + dr + " 0 0,1 " 
            + d.target.x + "," 
            + d.target.y;
  });
    node.attr("transform", nodeTransform);    
  }
}

/**
 * Gives the coordinates of the border for keeping the nodes inside a frame
 * http://bl.ocks.org/mbostock/1129492
 */ 
function nodeTransform(d) {
  d.x =  Math.max(maxNodeSize, Math.min(w - (d.imgwidth/2 || 16), d.x));
    d.y =  Math.max(maxNodeSize, Math.min(h - (d.imgheight/2 || 16), d.y));
    return "translate(" + d.x + "," + d.y + ")";
   }
/**
 * Toggle children on click.
 */ 
function click(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  update();
}

/**
 * Returns a list of all nodes under the root.
 */ 
function flatten(root) {
  var nodes = []; 
  var i = 0;
  function recurse(node) {
    if (node.children) 
      node.children.forEach(recurse);
    if (!node.id) 
      node.id = ++i;
    nodes.push(node);
  }
  recurse(root);
  return nodes;
} 

</script>
</body>
</html>

marvel.json

{
 "name": "marvel",
 "img": "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/marvel.png",
 "children": [
  {
   "name": "Heroes",
   "children": [
    {
      "hero": "Spider-Man",
      "name": "Peter Benjamin Parker", 
      "link": "http://marvel.com/characters/54/spider-man",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_spiderman.png",
      "size": 40000,
      "popularity": 1
    },
    {
      "hero": "CAPTAIN MARVEL",
      "name": "Carol Danvers", 
      "link": "http://marvel.com/characters/9/captain_marvel",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_captainmarvel.png",
      "size": 40000,
      "popularity": 3
    },
    {
      "hero": "HULK", 
      "name": "Robert Bruce Banner",
      "link": "http://marvel.com/characters/25/hulk",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_hulk.png",
      "size": 40000,
      "popularity": 6
    },
    {
      "hero": "Black Widow", 
      "name": "Natalia 'Natasha' Alianovna Romanova",
      "link": "http://marvel.com/characters/6/black_widow",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_blackwidow.png",
      "size": 40000,
      "popularity": 7
    },
    {
      "hero": "Daredevil", 
      "name": "Matthew Michael Murdock",
      "link": "http://marvel.com/characters/11/daredevil",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_daredevil.png",
      "size": 40000,
      "popularity": 7
    },
    {
      "hero": "Wolverine", 
      "name": "James Howlett",
      "link": "http://marvel.com/characters/66/wolverine",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_wolverine.png",
      "size": 40000,
      "popularity": 8
    },
    {
      "hero": "Captain America", 
      "name": "Steven Rogers",
      "link": "http://marvel.com/characters/8/captain_america",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_captainamerica.png",
      "size": 40000,
      "popularity": 9
    },
    {
      "hero": "Iron Man", 
      "name": "Anthony Edward 'Tony' Stark",
      "link": "http://marvel.com/characters/29/iron_man",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_ironman.png",
      "size": 40000,
      "popularity": 4
    },
    {
      "hero": "THOR", 
      "name": "Thor Odinson",
      "link": "http://marvel.com/characters/60/thor",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/top_thor.png",
      "size": 40000,
      "popularity": 5
    }
  ]
  },
  {
   "name": "Villains",
   "children": [
    {
      "hero": "Dr. Doom",
      "name": "Victor von Doom", 
      "link": "http://marvel.com/characters/13/dr_doom",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/drdoom.png",
      "size": 40000,
      "popularity": 6
    },
    {
      "hero": "Mystique",
      "name": "Unrevealed", 
      "link": "http://marvel.com/characters/1552/mystique",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/mystique.png",
      "size": 40000,
      "popularity": 8
    },
    {
      "hero": "Red Skull",
      "name": "Johann Shmidt", 
      "link": "http://marvel.com/characters/1901/red_skull",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/redskull.png",
      "size": 40000,
      "popularity": 9
    },
    {
      "hero": "Ronan",
      "name": "Ronan", 
      "link": "http://marvel.com/characters/49/ronan",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/ronan.png",
      "size": 40000,
      "popularity": 8
    },
    {
      "hero": "Magneto",
      "name": "Max Eisenhardt", 
      "link": "http://marvel.com/characters/35/magneto",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/magneto.png",
      "size": 40000,
      "popularity": 8
    },
    {
      "hero": "Thanos",
      "name": "Thanos", 
      "link": "http://marvel.com/characters/58/thanos",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/thanos.png",
      "size": 40000,
      "popularity": 7
    },
    {
      "hero": "Black Cat",
      "name": "Felicia Hardy", 
      "link": "http://marvel.com/characters/271/black_cat",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/blackcat.png",
      "size": 40000,
      "popularity": 6
    }
   ]
  },
  {
   "name": "Teams",
   "children": [
    {
      "hero": "Avengers",
      "name": "", 
      "link": "http://marvel.com/characters/68/avengers",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/avengers.png",
      "size": 40000,
      "popularity": 6
    },
    {
      "hero": "Guardians of the Galaxy",
      "name": "", 
      "link": "http://marvel.com/characters/70/guardians_of_the_galaxy",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/gofgalaxy.png",
      "size": 40000,
      "popularity": 5
    },
    {
      "hero": "Defenders",
      "name": "", 
      "link": "http://marvel.com/characters/534/defenders",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/defenders.png",
      "size": 40000,
      "popularity": 2
    },
    {
      "hero": "X-Men",
      "name": "", 
      "link": "http://marvel.com/characters/71/x-men",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/xmen.png",
      "size": 40000,
      "popularity": 3
    },
    {
      "hero": "Fantastic Four",
      "name": "", 
      "link": "http://marvel.com/characters/69/fantastic_four",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/fantasticfour.png",
      "size": 40000,
      "popularity": 3
    },
    {
      "hero": "Inhumans",
      "name": "", 
      "link": "http://marvel.com/characters/1040/inhumans",
      "img":  "https://dl.dropboxusercontent.com/u/19954023/marvel_force_chart_img/inhumans.png",
      "size": 40000,
      "popularity": 9
    }
   ]
  }  

您可以使用d3.js的.filter()特性。将平面化的json记录存储在全局变量中。为"所有"answers"流行"按钮设置一个onclick侦听器。'popular'按钮的onclick监听器可以是这样的:

function filterPopular(){
  tempNodes = nodes.filter(function(d){
    return !('popularity' in d) || d.popularity>5;
  });
  update(tempNodes);
}

.filter()的本质是保留回调函数返回true的记录。在这种情况下,没有人气字段的记录(非叶节点)或人气大于5的记录将保留在tempNodes中。我将过滤的记录存储到一个新的变量中,以便在单击"所有"按钮时全局维护记录。使用tempNodes调用update。节点现在将消失,但从父节点到已删除的子节点的链接将保留。你必须想办法删除这些链接。希望这对你有所帮助!