首页 > 解决方案 > D3.js 多个 svg 事件未触发

问题描述

尝试使用 d3.js 显示两棵树。添加第二棵树后,缩放或单击事件都不适用于第一个 SVG。我通过限定特定的 svg 类名称添加了缩放和事件。还是不行。请提供任何帮助

<script src="http://d3js.org/d3.v3.min.js"></script>

// ************** Generate the tree diagram  *****************
        var margin = {
                top: 20,
                right: 120,
                bottom: 20,
                left: 120
            },
            width = 900 - margin.right - margin.left,
            height = 500 - margin.top - margin.bottom;

        var i = 0,
            duration = 750,
            root;

        var nodeWidth = 150;
        var nodeHeight = 30;

        var tree1 = d3.layout.tree()
            .size([height, width])
            .nodeSize([nodeWidth, nodeHeight])
            .separation(function(a, b) {
                return ((a.parent == root) && (b.parent == root)) ? 0.2 : 0.3;
            });

        var tree2 = d3.layout.tree()
            .size([height, width])
            .nodeSize([nodeWidth, nodeHeight])
            .separation(function(a, b) {
                return ((a.parent == root) && (b.parent == root)) ? 0.2 : 0.3;
            });

        var treeDict = {};
        treeDict["_lhs"] = tree1;
        treeDict["_rhs"] = tree2;

        var diagonal = d3.svg.diagonal()
            .projection(function(d) {
                return [d.y, d.x];
            })
            .source(function(d) {
                return {
                    x: d.source.x,
                    y: d.source.y
                };
            })
            .target(function(d) {
                return {
                    x: d.target.x,
                    y: d.target.y
                };
            });

        var posCSS;
        var pos_CSS;
        /*
        .call(d3.behavior.zoom().on("zoom", function () { d3.select(posCSS).select(".svg_1").select(".svg_2").attr("transform", d3.event.transform) }))
        */
        var ret = drawTree(".lhs", tree1);

        function drawTree(cssPos, treeData) {
            posCSS = cssPos
            pos_CSS = cssPos.replace(/[&\/\\#, +()$~%.'":*?<>{}]/g, '_');

            var svg = d3.select("body").select(posCSS).append("svg:svg")
                .attr("class", "svg_1" + pos_CSS)
                .attr("width", width)
                .attr("height", height)
                .style("background-color", "#EEEEEE")
                .style("overflow", "scroll")
                .call(d3.behavior.zoom().scaleExtent([0.5, 5]).on("zoom", zoom))
                .append("svg:g")
                .attr("class", "svg_2")
                .append("svg:g")
                .attr("class", "svg_3")
                .attr("transform", "translate(" + (margin.left) + "," + (margin.top + height / 2) + ")");
            //without svg_3 when we select the graph first time, it moves to top left and then we need to drag..so leave it

            /*
                d3.select(posCSS).select(".svg_1")
                      .call(d3.behavior.zoom()
                      .scaleExtent([0.5, 5])
                      .on("zoom", zoom)); 
            */

            root = treeData[0];
            root.x0 = height / 2;
            root.y0 = 0;

            update(root);
        }

        function update(source) {
            //var nodeHeight = 50, nodeWidth = 100;
            // Compute the new tree layout.
            var nodes = treeDict[pos_CSS].nodes(root).reverse(),
                links = treeDict[pos_CSS].links(nodes);

            // Normalize for fixed-depth.
            //For Right to Left
            //nodes.forEach(function(d) { d.y = width - (d.depth * 180); });

            //For Left to Right
            nodes.forEach(function(d) {
                d.y = d.depth * 180;
            });

            // Update the nodes
            //var node = svg.selectAll("g.node")
            var node = d3.select("div" + posCSS).select("svg.svg_1" + pos_CSS).select("g.svg_2").select("g.svg_3").selectAll("g.node")
                .data(nodes, function(d) {
                    return d.id || (d.id = ++i);
                });

            //var arrow = svg.append("svg:defs").selectAll("marker")
            var arrow = d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2").select(".svg_3").append("svg:defs").selectAll("marker")
                .data(["end"]) // Different link/path types can be defined here
                .enter().append("svg:marker") // This section adds in the arrows
                .attr("id", String)
                .attr("viewBox", "0 -5 10 10")
                .attr("refX", 0)
                .attr("refY", 0)
                .attr("markerWidth", 6)
                .attr("markerHeight", 6)
                .attr("orient", "auto")
                .attr("class", "arrow")
                .append("svg:path")
                .attr('d', 'M10,-5L0,0L10,5');

            // Enter any new nodes at the parent's previous position.
            var nodeEnter = node.enter().append("g")
                .attr("class", "node")
                .attr("transform", function(d) {
                    return "translate(" + source.x0 + "," + source.y0 + ")";
                })
                //.on("click", click);
                // Toggle children on click.
                .on("click", function(d) {
                    if (d.children) {
                        d._children = d.children;
                        d.children = null;
                    } else {
                        d.children = d._children;
                        d._children = null;
                    }
                    update(d);
                });

            nodeEnter.append("rect")
                .attr("width", nodeWidth)
                .attr("height", nodeHeight)
                .attr("stroke", "black")
                .attr("fill", "blue")
                .style("fill", function(d) {
                    return d._children ? "lightsteelblue" : "#fff";
                });

            nodeEnter.append("foreignObject")
                .attr('x', -5)
                .attr('y', -10)
                .append("xhtml:body")
                .append("xhtml:div")
                .style({
                    width: nodeWidth + 'px',
                    height: nodeHeight + 'px',
                    "font-size": "10px",
                    "background-color": "white"
                }).html(function(d) {
                    return '<b>' + d.funcName + '<br>' + '<A HREF="http://127.0.0.1:5000" target="_blank" >' + d.modName + '</A></b>'
                });;

            var nodeUpdate = node.transition()
                .duration(duration)
                .attr("transform", function(d) {
                    if (d.parent == "null") {
                        d.y = 700;
                        //d.x = 10;
                    }
                    return "translate(" + d.y + "," + d.x + ")";
                });

            nodeUpdate.select("rect")
                .attr("r", 10)
                .style("fill", function(d) {
                    return d._children ? "lightsteelblue" : "#fff";
                });
            nodeUpdate.select("text")
                .style("fill-opacity", 1);

            // Transition exiting nodes to the parent's new position.
            var nodeExit = node.exit().transition()
                .duration(duration)
                .attr("transform", function(d) {
                    return "translate(" + source.y + "," + source.x + ")";
                })
                .remove();

            nodeExit.select("circle")
                //nodeExit.select("rect")
                .attr("r", 1e-6);
            nodeExit.select("text")
                .style("fill-opacity", 1e-6);

            // Update the links
            var link = d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2").select(".svg_3").selectAll("path.link")
                .data(links, function(d) {
                    return d.target.id;
                });
            // Enter any new links at the parent's previous position.
            link.enter().insert("path", "g")
                .attr("marker-end", "url(#end)")
                .attr("class", "link")
                .attr("d", function(d) {
                    var valX = 15,
                        valY = 10
                    var o = {
                        x: source.x0 + valX,
                        y: source.y0
                    };
                    return diagonal({
                        source: o,
                        target: o
                    });
                });
            // Transition links to their new position.
            link.transition()
                .duration(duration)
                .attr("d", function(d) {
                    var valX = 15,
                        valY = 10
                    var s = {
                            x: d.source.x + valX,
                            y: d.source.y + nodeWidth + valY - 5
                        },
                        t = {
                            x: d.target.x + valX,
                            y: d.target.y - valY
                        }
                    return diagonal({
                        source: s,
                        target: t
                    });

                });
            // Transition exiting nodes to the parent's new position.
            link.exit().transition()
                .duration(duration)
                .attr("d", function(d) {
                    var valX = 15,
                        valY = 10
                    var o = {
                        x: source.x + valX,
                        y: source.y + nodeWidth + valY
                    };
                    return diagonal({
                        source: o,
                        target: o
                    });
                })
                .remove();
            // Stash the old positions for transition.
            nodes.forEach(function(d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });

            node.on("mouseover", function(p) {

                var nodes = [];
                nodes.push(p);

                while (p.parent) {
                    p = p.parent;
                    nodes.push(p);
                }

                //color the links
                link.filter(function(d) {
                    if (nodes.indexOf(d.target) !== -1) return true;
                }).style("stroke", "orange");

                //color the nodes 
                node.filter(function(d) {
                    if (nodes.indexOf(d) !== -1) return true;
                }).style("fill", "steelblue");

            });

            node.on("mouseout", function(p) {

                var nodes = [];
                nodes.push(p);

                while (p.parent) {
                    p = p.parent;
                    nodes.push(p);
                }

                //color the links
                link.filter(function(d) {
                    if (nodes.indexOf(d.target) !== -1) return true;
                }).style("stroke", "#ccc");

                //color the nodes 
                node.filter(function(d) {
                    if (nodes.indexOf(d) !== -1) return true;
                }).style("fill", "#ccc");

            });

        }

        function zoom() {
            var realWidth = window.innerWidth - 80;
            var realHeight = window.innerHeight - 480;
            var scale = d3.event.scale,
                translation = d3.event.translate,
                tbound = -height * scale,
                bbound = height * scale,
                lbound = (-width + 240) * scale,
                rbound = (width - 240) * scale;
            translation = [
                Math.max(Math.min(translation[0], rbound), lbound),
                Math.max(Math.min(translation[1], bbound), tbound)
            ];
            d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2")
                .attr("transform", "translate(" + translation + ")" +
                    " scale(" + scale + ")");
        }
    </script>
    <div class="lhs">
        <script>
            var tree2 = [{
                "children": [{
                    "children": [{
                        "count": 1,
                        "funcName": "main",
                        "modName": "bash-5.0/array.c"
                    }, {
                        "count": 1,
                        "funcName": "print_array_assignment",
                        "modName": "bash-5.0/arrayfunc.c"
                    }, {
                        "count": 1,
                        "funcName": "array_var_assignment",
                        "modName": "bash-5.0/subst.c"
                    }, {
                        "count": 1,
                        "funcName": "make_env_array_from_var_list",
                        "modName": "bash-5.0/variables.c"
                    }],
                    "count": 1,
                    "funcName": "array_to_assign",
                    "modName": "bash-5.0/array.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "print_assoc_assignment",
                        "modName": "bash-5.0/arrayfunc.c"
                    }, {
                        "count": 1,
                        "funcName": "array_var_assignment",
                        "modName": "bash-5.0/subst.c"
                    }, {
                        "count": 1,
                        "funcName": "make_env_array_from_var_list",
                        "modName": "bash-5.0/variables.c"
                    }],
                    "count": 2,
                    "funcName": "assoc_to_assign",
                    "modName": "bash-5.0/assoc.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "execute_disk_command",
                        "modName": "bash-5.0/execute_cmd.c"
                    }],
                    "count": 1,
                    "funcName": "printable_filename",
                    "modName": "bash-5.0/general.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "string_var_assignment",
                        "modName": "bash-5.0/subst.c"
                    }, {
                        "count": 1,
                        "funcName": "string_transform",
                        "modName": "bash-5.0/subst.c"
                    }],
                    "count": 1,
                    "funcName": "sh_quote_reusable",
                    "modName": "bash-5.0/lib/sh/shquote.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "do_assignment_internal",
                        "modName": "bash-5.0/subst.c"
                    }, {
                        "count": 1,
                        "funcName": "assign_in_env",
                        "modName": "bash-5.0/variables.c"
                    }],
                    "count": 1,
                    "funcName": "xtrace_print_assignment",
                    "modName": "bash-5.0/print_cmd.c"
                }, {
                    "children": [{
                        "count": 2,
                        "funcName": "execute_simple_command",
                        "modName": "bash-5.0/execute_cmd.c"
                    }, {
                        "count": 1,
                        "funcName": "xtrace_print_for_command_head",
                        "modName": "bash-5.0/print_cmd.c"
                    }, {
                        "count": 1,
                        "funcName": "xtrace_print_select_command_head",
                        "modName": "bash-5.0/print_cmd.c"
                    }],
                    "count": 1,
                    "funcName": "xtrace_print_word_list",
                    "modName": "bash-5.0/print_cmd.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "print_heredocs",
                        "modName": "bash-5.0/print_cmd.c"
                    }, {
                        "count": 2,
                        "funcName": "print_redirection_list",
                        "modName": "bash-5.0/print_cmd.c"
                    }],
                    "count": 1,
                    "funcName": "print_redirection",
                    "modName": "bash-5.0/print_cmd.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "printenv_builtin",
                        "modName": "bash-5.0/examples/loadables/printenv.c"
                    }, {
                        "count": 1,
                        "funcName": "print_assignment",
                        "modName": "bash-5.0/variables.c"
                    }],
                    "count": 1,
                    "funcName": "print_var_value",
                    "modName": "bash-5.0/variables.c"
                }, {
                    "children": [{
                        "count": 1,
                        "funcName": "push_heredoc",
                        "modName": "bash-5.0/y.tab.c"
                    }, {
                        "count": 1,
                        "funcName": "yyerror",
                        "modName": "bash-5.0/y.tab.c"
                    }],
                    "count": 1,
                    "funcName": "report_syntax_error",
                    "modName": "bash-5.0/y.tab.c"
                }],
                "count": 1,
                "funcName": "ansic_quote",
                "modName": "FileName.c"
            }];
            var ret = drawTree(".lhs", tree2);
        </script>
    </div>
    <div class="rhs">
        <script>
            var ret = drawTree(".rhs", tree2);
        </script>
.node {
            cursor: pointer;
        }
        
        .link {
            fill: none;
            stroke: #aaa;
            stroke-width: 2px;
        }
        
        .lhs {
            position: fixed;
            top: 0;
            left: 0px;
            border: 3px solid #73AD21;
        }
        
        .rhs {
            position: fixed;
            top: 0;
            right: 0px;
            border: 3px solid #73AD21;
        }
<html>
<body>
    <div class="lhs">
        <script>
            var ret = drawTree(".lhs", treeData);
        </script>
    </div>
        <div class="rhs">
        <script>
            var ret = drawTree(".rhs", treeData);
        </script>
    </div>
<body>

尝试使用 d3.js 显示两棵树。添加第二棵树后,缩放或单击事件都不适用于第一个 SVG。我通过限定特定的 svg 类名称添加了缩放和事件。还是不行。请提供任何帮助

标签: htmld3.jssvg

解决方案


我的错。我正在使用全局变量 pos_CSS 操作两个 SVG。添加所有元素后,当焦点移向给定的 SVG(比如鼠标单击)时,我忘记相应地更新 pos_CSS(即 _lhs 或 _rhs)。通过修复 pos_CSS 的更新,我的问题得到了解决。感谢您为帮助我所做的一切努力。


推荐阅读