0

I would like to create a Search function for all my circle in D3.js. The problem is I can't select a particulary item from my textbox but I can select all items for hide them. Other question, is it a good solution to search an item to hide it ? This is my function to hide item :

function myFunction(){
    var myBubble = document.getElementById("targetNode").value;
    var theNode = d3.select(myBubble.id);
        d3.selectAll("circle").style("opacity","0");
        d3.selectAll("text").style("opacity","0");
        theNode.style("opacity","1");
}

This is an online example of the problem : https://plnkr.co/edit/tFgMhomgn2sKazK674Kl?p=preview Thanks a lot !

Anonymous
  • 468
  • 5
  • 26

3 Answers3

2

Select all nodes first and then filter the desired one by comparing the data bound to the node:

function hideItem(){
    var itemName = document.getElementById("targetNode").value;
    var theNode = d3.selectAll(".node")
                    .filter(function(d) { return d.className === itemName });
    d3.selectAll(".node").style("opacity","0");
    theNode.style("opacity","1");
}

https://plnkr.co/edit/pF4EYzE4V3x4T5KMILEM

Lukasz Wiktor
  • 19,644
  • 5
  • 69
  • 82
  • Thanks, it works ! It's too bad there is not a "real" function to search it beacause I can't pack() to center it. – Anonymous May 02 '16 at 09:28
  • It would be possible but with another approach. Instead of modifying opacity you would need to remove unwanted nodes. The essence of this approach is that you rebuild the chart every time the data changes. D3 includes a special concept for that: enter, update and exit selections. You're actually using the enter() selection. You can think of the search function as it would produce new data for your chart. – Lukasz Wiktor May 02 '16 at 09:51
1

Here it is. You can easily find that you haven't given ids' to the nodes but you are getting it. You can do it like the plnkr shared.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Hide item</title>
</head>

<body>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>

    var diameter = 900,
            format = d3.format(",d"),
            color = d3.scale.category20c();

    var bubble = d3.layout.pack()
            .sort(null)
            .size([diameter, diameter])
            .value(function(d) { return (d.life+1); })
            .padding(1.5);

    var svg = d3.select("body").append("svg")
            .attr("width", diameter)
            .attr("height", diameter)
            .attr("class", "bubble");

    d3.json("./data.json", function(error, root) {
        if (error) throw error;

        var node = svg.selectAll(".node")
                .data(bubble.nodes(classes(root))
                 .filter(function(d) { return !d.children; }))
                .enter().append("g")
                .attr("class", "node")
                .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        node.append("title")
                .text(function(d) { return d.className + ": " + format(d.value); });

        node.append("circle")
                .attr("r", function(d) { return d.r; })
                .style("opacity","1")
                .style("fill", function(d){
                    if (d.level == 1){
                        return "red"
                    } else if (d.level == 2){
                        return "orange"
                    } else if (d.level == 3){
                        return "#66a3ff"
                    } else {
                        return "green"
                    }
                });

        var value = function(d) { return d.className.substring(0, d.r / 3); };
        node.append("text")
                .attr("dy", ".3em")
                .style("text-anchor", "middle")
                .attr("id", value)
                .text(value)
                .style("opacity","1");
    });

    // Returns a flattened hierarchy containing all leaf nodes under the root.
    function classes(root) {
        var classes = [];
        function recurse(name, node) {
            if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
            else classes.push({packageName: name, className: node.name, value: node.life,  life: node.life, level: node.level});
        } 
        recurse(null, root);
        return {children: classes};
    }
    d3.select(self.frameElement).style("height", diameter + "px");

</script>
<input id="targetNode" name="targetNode" type="text" />
<button onclick="hideItem()">grow node</button>
<br>

<script type="text/javascript">
    function hideItem(){
        var itemName = document.getElementById("targetNode").value;
        console.log(itemName);
        var theNode = d3.select("#" + itemName);
        console.log(theNode);
            d3.selectAll("circle").style("opacity","0");
            d3.selectAll("text").style("opacity","0");
            d3.select(theNode.node().parentNode).selectAll("circle,text").style("opacity","1");
    }
</script>
</body>

Plnkr

Surya Purohit
  • 1,090
  • 1
  • 9
  • 29
0

Because you need to change the opacity of all your circles, the most efficient way doing this might be to select all circles' groups and selectively apply the opacity. The value to be returned can be determined withing the callback provided to .attr("opacity", cb) by comparing the bound data's className to the value of your input field:

function hideItem(){
    var itemName = document.getElementById("targetNode").value;
    d3.selectAll(".node")
      .attr("opacity", function(d) {
        return d.className === itemName ? "1" : "0";
      })
}

See this updated Plunk.

altocumulus
  • 21,179
  • 13
  • 61
  • 84