按钮onclick后,为SVG节点添加多个工具提示

时间:2015-03-12 18:59:46

标签: javascript jquery svg d3.js

我正在尝试显示多个SVG节点的工具提示,这些节点具有基于按钮单击的相关属性。

我一直在关注创建工具提示的Scott Murrays一书,但这似乎适用于在事件悬停后显示工具提示。我的程序在某种意义上是不同的,我想按一个按钮[查找相关的标题],并让它显示具有相同标题属性的节点的工具提示。

这是我为工具提示创建的div

<div id="tooltip" class="hidden">
    <p><strong>Important Label heading</strong></p>
    <p><span id="value">100</span>%</p>
</div>

这是样式表:

#tooltip {
        position: absolute;
        width: 200px;
        height: auto;
        padding: 10px;
        background-color: white;
        -webkit-border-radius: 10px;
        -moz-border-radius: 10px;
        border-radius: 10px;
        -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
        -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
        box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
        pointer-events: none;
}

#tooltip.hidden {
        display: none;
}

#tooltip p {
        margin: 0;
        font-family: sans-serif;
        font-size: 16px;
        line-height: 20px;
}

这是我创建每个节点的方式:

var node = svg.selectAll(".node")
        .data(graph.nodes).enter()
        .append("circle")
        .attr("class", function (d) { console.log("Represents: " + d.properties.represents); return "node "+ d.type.toString() })
        .attr("r", radius)
        .style("fill", function(d) {return d.colr; })
        .call(force.drag);

// html title attribute
node.append("title")
        .text(function (d) { return d.name; })

现在,当单击某个节点时,程序会生成用于查找具有相同属性的节点的按钮。 这里我们只是尝试设置按下findTitlesBtn时的工具提示。

node.on("click", function(n)
                {
                /// Several more lines of code ///
                    getTitle = n.properties.title;

                    //Dynamically create button for finding related Titles
                    if (getTitle !== undefined) {
                        //Create the button element
                        var findTitlesBtn = document.createElement("BUTTON"); 

                        //Create the button label, and add it to the button
                        var title = document.createTextNode("Find Related Titles");      
                        findTitlesBtn.appendChild(title);

                        //Call findTitle function when button is clicked
                        findTitlesBtn.onclick = findTitle;

                        //Add button to the 'displayOptions' div inside the console
                        document.getElementById("displayOptions").appendChild(findTitlesBtn);
                    }

最后,单击按钮时调用的函数。我相信它应该在这个功能中。在我筛选节点后(基于它们是否具有相同的title属性),每个节点都会调用一个使其工具提示可见的函数。 过滤的节点是我想要显示工具提示的节点。

//Function used to find nodes with related 'Title' properties
    function findTitle() {

        //Return color of nodes back to normal
        svg.selectAll(".node").style("fill", function(d) { return d.colr; });

        //Filter through all nodes to find matching titles, color them yellow
        svg.selectAll(".node")
        .filter(function(d) { return d.properties.title == getTitle; })
        .style('fill', 'yellow')
        .onload = function(d) {

            //Get this bar's x/y values, then augment for the tooltip
            var xPosition = parseFloat(d3.select(this).attr("x"));
            var yPosition = parseFloat(d3.select(this).attr("y"));

            //Update the tooltip position and value
            d3.select("#tooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px")
            .select("#value")
            .text(d);

            //Show the tooltip
            d3.select("#tooltip").classed("hidden", false);
        }
    }

然而,这不起作用。我无法在网上找到与此特定问题或文档相关的任何内容,以便我尝试做什么。我有很少的Javascript经验,这是我第一次使用SVG / D3。关于我当前实施的错误的任何建议将不胜感激!虽然我已经添加了上述代码的所有相关部分,但为了完整起见,我已附上完整的脚本。

以下是完整的源代码:

  <!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>

<div id="console">
<h2>Find all matches:</h3>
<div id="displayOptions"></div>

<div id="metainfo"></div>
</div>

<div id="graph">
</div>

<div id="tooltip" class="hidden">
    <p><strong>Important Label heading</strong></p>
    <p><span id="value">100</span>%</p>
</div>

<style type="text/css">
    .node { stroke: #222; stroke-width: 1.5px; }
    .node.Column { fill: #777; }
    .node.Table { fill: #BBB; }
    .node.JoinTable { fill: #999}
    .node.Dataset { fill: #333}
    .link { stroke: #999; stroke-width: 7px; }
    div {height: 100%;}
    html {height: 100%;}
    body {height: 100%;}
</style>


<script type="text/javascript">
    var width = 1200, height = 800, radius = 20;

    var force = d3.layout.force()
            .charge(-1000).linkDistance(150).size([width, height]);

    var svg = d3.select("#graph").append("svg")
            .attr("width", "100%").attr("height", "100%")
            .attr("pointer-events", "all");

    //var currRepresents = "null";



    d3.json("/Justin/graph", function(error, graph) {
        if (error) return;

        force.nodes(graph.nodes).links(graph.links).start();

        var link = svg.selectAll(".link")
                .data(graph.links).enter()
                .append("line").attr("class", "link");

        var node = svg.selectAll(".node")
                .data(graph.nodes).enter()
                .append("circle")
                .attr("class", function (d) { console.log("Represents: " + d.properties.represents); return "node "+ d.type.toString() })
                .attr("r", radius)
                .style("fill", function(d) {return d.colr; })
                .call(force.drag);

        // html title attribute
        node.append("title")
                .text(function (d) { return d.name; })


        var state = false;
        var last = null;
        var current = null;
        node.on("click", function(n)
                {
                    //Return color of nodes back to normal
                    svg.selectAll(".node").style("fill", function(d) { return d.colr; });

                    //Remove buttons from previous mouse click
                    var getOptionsDiv = document.getElementById("displayOptions");
                    while (getOptionsDiv.hasChildNodes()) { 
                        getOptionsDiv.removeChild(getOptionsDiv.lastChild);
                    }


                    //Get Represents property from currently selected node
                    currRepresents = n.properties.represents;

                    //Add data to meta info div
                    var metainf = "";
                    metainf = metainf.concat("Title: ", n.name, "<br/>Label: ", n.type, "<br/>Represents: ", n.properties.represents, 
                    "<br/>Column Type: ", n.properties.columntype, "<br/>Semantic Relation: ", n.properties.semanticrelation);
                    console.log(metainf);
                    d3.select("#metainfo")
                        .html(metainf);

                    last = current;
                    current = d3.select(this);
                    current.style('fill', 'red');
                    last.style('fill', function(d) { return d.colr; });

                    getTitle = n.properties.title;
                    getRepresents = n.properties.represents;
                    getColumnType = n.properties.columntype;
                    getSemanticRelation = n.properties.semanticrelation;

                    //Dynamically create button for finding related Titles
                    if (getTitle !== undefined) {
                        //Create the button element
                        var findTitlesBtn = document.createElement("BUTTON"); 

                        //Create the button label, and add it to the button
                        var title = document.createTextNode("Find Related Titles");      
                        findTitlesBtn.appendChild(title);

                        //Call findTitle function when button is clicked
                        findTitlesBtn.onclick = findTitle;

                        //Add button to the 'displayOptions' div inside the console
                        document.getElementById("displayOptions").appendChild(findTitlesBtn);
                    }

                    //Dynamically create button for finding related Represents
                    if (getRepresents !== undefined) {
                        //Create the button element
                        var findRepresentsBtn = document.createElement("BUTTON");

                        //Create the button label, and add it to the button 
                        var title = document.createTextNode("Find Related Represents");       
                        findRepresentsBtn.appendChild(title);

                        //Call findRepresents function when button is clicked
                        findRepresentsBtn.onclick = findRep;

                        //Add button to the 'displayOptions' div inside the console
                        document.getElementById("displayOptions").appendChild(findRepresentsBtn);
                    }

                    //Dynamically create button for finding related Column Types
                    if (getColumnType !== undefined) {
                        //Create the button element
                        var findColumnTypeBtn = document.createElement("BUTTON"); 

                        //Create the button label, and it to the button
                        var title = document.createTextNode("Find Related Column Types");       
                        findColumnTypeBtn.appendChild(title);

                        //Call findColType function when button is clicked
                        findColumnTypeBtn.onclick = findColType;

                        //Add button to the 'displayOptions' div inside the console
                        document.getElementById("displayOptions").appendChild(findColumnTypeBtn);
                    }

                    //Dynamically create button for finding related Semantic Relations
                    if (getSemanticRelation !== undefined) {
                        //Create the button element
                        var findSemanticRelationsBtn = document.createElement("BUTTON"); 

                        //Create the button label, and it to the button
                        var title = document.createTextNode("Find Related Semantic Relations");       
                        findSemanticRelationsBtn.appendChild(title);

                        //Call findSemRel function when button is clicked
                        findSemanticRelationsBtn.onclick = findSemRel;

                        //Add button to the 'displayOptions' div inside the console
                        document.getElementById("displayOptions").appendChild(findSemanticRelationsBtn);
                    }



                });



        // force feed algo ticks
        force.on("tick", function() {

             node.attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
             .attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });


            link.attr("x1", function(d) { return d.source.x; })
                    .attr("y1", function(d) { return d.source.y; })
                    .attr("x2", function(d) { return d.target.x; })
                    .attr("y2", function(d) { return d.target.y; });

            node.attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; });
        });



    });

    function findRepresents() {
        if (currRepresents == "null") {
            console.log("No node is clicked on currently!");
        } else {
            console.log(currRepresents);
        }

    }

    //Function used to find nodes with related 'Title' properties
    function findTitle() {

        //Return color of nodes back to normal
        svg.selectAll(".node").style("fill", function(d) { return d.colr; });

        //Filter through all nodes to find matching titles, color them yellow
        svg.selectAll(".node")
        .filter(function(d) { return d.properties.title == getTitle; })
        .style('fill', 'yellow')
        .onload = function(d) {

            //Get this bar's x/y values, then augment for the tooltip
            var xPosition = parseFloat(d3.select(this).attr("x"));
            var yPosition = parseFloat(d3.select(this).attr("y"));

            //Update the tooltip position and value
            d3.select("#tooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px")
            .select("#value")
            .text(d);

            //Show the tooltip
            d3.select("#tooltip").classed("hidden", false);
        }
    }

    //Function used to find nodes with related 'Represents' properties
    function findRep() {      

        //Return color of nodes back to normal
        svg.selectAll(".node").style("fill", function(d) { return d.colr; });

        //Filter through all nodes to find matching represents, color them blue
        svg.selectAll(".node")
        .filter(function(d) { return d.properties.represents == getRepresents; })
        .style('fill', 'blue');

    }

    //Function used to find nodes with related 'Column Type' properties
    function findColType() {        

        //Return color of nodes back to normal
        svg.selectAll(".node").style("fill", function(d) { return d.colr; });

        //Filter through all nodes to find matching column types, color them green
        svg.selectAll(".node")
        .filter(function(d) { return d.properties.columntype == getColumnType; })
        .style('fill', 'green');

    }

    //Function used to find nodes with related 'Semantic Relation' properties
    function findSemRel() {     

        //Return color of nodes back to normal
        svg.selectAll(".node").style("fill", function(d) { return d.colr; });

        //Filter through all nodes to find matching semantic relations, color them orange
        svg.selectAll(".node")
        .filter(function(d) { return d.properties.semanticrelation == getSemanticRelation; })
        .style('fill', 'orange');

    }


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

修改 以下是创建JSON的Java代码:

@SuppressWarnings("unchecked")
    public Map<String, Object> graph(int limit) {

        Iterator<Map<String,Object>> result = cypher.query(
                "match (c)-[:BELONGS_TO]->(p) " +
                "return c.title as childName, labels(c) as childType, ID(c) as childId, c as child, p.title as parentName, labels(p) as parentType, ID(p) as parentId, p as parent ", 
                map("1",limit));

         List nodes = new ArrayList();
         List rels= new ArrayList();

         int i = 0;
         //Iterate through each row of the resulting cypher query
         while (result.hasNext()) 
         {

            //Row has a dataset, a table, and a collection of columns
            Map<String, Object> row = result.next();

            //Add the child node if it is not already there
            Map<String, Object> childNode = map("id", row.get("childId"), "name", row.get("childName"), "type", row.get("childType"), "properties", row.get("child"));
            int source = nodes.indexOf(childNode);
            if (source == -1) 
            {
                nodes.add(childNode);
                source = i++;
            }

            //Add the parent node if it is not already there
            Map<String, Object> parentNode = map("id", row.get("parentId"), "name", row.get("parentName"), "type", row.get("parentType"), "properties", row.get("parent"));
            int target = nodes.indexOf(parentNode);
            if (target == -1) 
            {
                nodes.add(parentNode);
                target = i++;
            }

            rels.add(map("source", source, "target", target));

         }
         return map("nodes", nodes, "links", rels);

     }

0 个答案:

没有答案