D3力布局图缩放功能

时间:2018-04-12 11:14:38

标签: javascript d3.js

我是js的新人,无法解决我自己面临的问题,所以我会很高兴得到任何建议或帮助。

在我的项目中,我创建了力布局图。 我应该做的是为我的图表添加放大和缩小功能。

我创建了一个小例子来展示我面临的问题。

function myGraph(el){
this.addNode = function (id, category, opened, parentT, name, nodeType, countLinks, dob, country, childsCount) {
            var parent = [];
            parent.push(parentT);
            nodes.push({ "id": id, "category": category,    "opened": opened, "parent": parent, "name": name, "nodeType": nodeType, "countLinks": countLinks, "dob": dob, "country": country, "childCount": childsCount });
            update();
        }

this.addLink = function (sourceId, targetId, type) {
            var sourceNode = findNode(sourceId);
            var targetNode = findNode(targetId);

            if ((sourceNode !== undefined) && (targetNode !== undefined)) {
                links.push({ "source": sourceNode, "target": targetNode, "type": type });
                update();
            }
        }

var findNode = function (id) {
            for (var i = 0; i < nodes.length; i++) {
                if (nodes[i].id === id)
                    return nodes[i]
            };
        }

var w = 360,
            h = 200;


var vis = this.vis = d3.select(el).append("svg:svg")
            .attr("id", "mySvg")
            .attr("width", w)
            .attr("height", h)
            .attr("viewBox", "0 0 " + w + " " + h)
            .call(d3.behavior.zoom().scaleExtent([-0.5, 1]).on("zoom", redraw))

var g = vis.append('svg:g')
            function redraw(e) {
                if (!e) e = window.event;
                if (e.type == "wheel" || e.shiftKey == true) {
                    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
                }
        }

var force = d3.layout.force()
            .gravity(0.05)
            .distance(100)
            .charge(-200)
            .size([w, h]);

var nodes = force.nodes(),
                links = force.links();
var hiddenType = [];

        g.append("g").attr("class", "links");
        g.append("g").attr("class", "nodes");

        var update = function () {
            for (var i=0; i<links.length; i++) {
                if (i != 0 &&
                    links[i].source == links[i-1].source &&
                    links[i].target == links[i-1].target) {
                        links[i].linknum = links[i-1].linknum + 1;
                    }
                else {links[i].linknum = 1;};
            };

            var myLink = g.select(".links").selectAll(".link");
            myLink.remove();
            var link = g.select(".links").selectAll(".link")
                .data(links);
            link.enter().append("polyline")
                .attr("class", "link")
                .attr("type", function (d) { return "link_" + d.type; })

            link.exit().remove();

            var node = g.select(".nodes").selectAll(".node")
                .data(nodes, function (d) { return d.id; })

            var nodeEnter = node.enter().append("g")
                .attr("class", "node")
                .attr("links", function (d) { return d.countLinks })
                .attr("type", function (d) { return d.nodeType })
                .on("mousedown", mousedown)
                .call(force.drag);

            nodeEnter.append("circle")
                .attr("r", "10px")
                .attr("x", "-8px")
                .attr("y", "-8px")
                .attr("width", "16px")
                .attr("height", "16px")
                .style("fill", "white")
                .style("stroke", "#ccc")

                        nodeEnter.append("rect")
                .attr("pointer-events", "none")
                .attr("class", "shape")
                .attr("width", "250px")
                .attr("height", "150px")
                .style("fill", "transparent")
            nodeEnter.append("text")
                .attr("pointer-events", "none")
                .attr("class", function (d) { return "nodetext_" + d.id })
                .attr("y", "-10")
                .text(function (d) { return d.id })

            nodeEnter.append("title")
                .text(function (d) { return d.id });

            node.exit().remove();

        function mousedown(d) {
                d.fixed = true;
            }

            force.on("tick", function () {

                link.attr("points", function(d){
                    if (d.source.y > d.target.y) {
                        return d.source.x + "," + d.source.y + " " + (d.source.x + ((d.target.x - d.source.x) / 2)) + "," + (d.target.y + ((d.source.y - d.target.y) / 2) + (15 * (d.linknum - 1))) + " " + d.target.x + "," + d.target.y;
                    }
                    if (d.source.y < d.target.y) {
                        return d.source.x + "," + d.source.y + " " + (d.source.x + ((d.target.x - d.source.x) / 2)) + "," + (d.source.y + ((d.target.y - d.source.y) / 2) + (15 * (d.linknum - 1))) + " " + d.target.x + "," + d.target.y;
                    }
                })

                node.attr("transform", function (d) {
                    if (d.fixed !== true) {
                        return "translate(" + d.x + "," + d.y + ")";
                    }
                    else {
                        return "translate(" + d.px + "," + d.py + ")";
                    }
                });
            });
                            force.start();
    }
          update();
}
graph = new myGraph("#graph");
graph.addNode("A")
graph.addNode("B")
graph.addNode("C")
graph.addLink("A", "B")
graph.addLink("A", "C")

https://jsfiddle.net/IMykytiv/nsxL8c52/

问题是:

在我的图表中,用户可以在该节点的位置固定后向任意方向拖动节点。当我添加缩放时,我无法拖动节点,因为缩放首先工作,所以我添加了条件,只有在按下shift键时缩放才有效。所以现在我可以拖动节点和缩放。

但是现在我遇到了一个问题,如果我拖动节点并尝试用鼠标滚轮进行缩放,它改变了变换而不是从鼠标位置而是从另一点变换,我无法理解为什么。如果我删除shift键条件缩放按预期工作。

1 个答案:

答案 0 :(得分:0)

我最终找到了解决方案并且它非常容易。 我没有按下按Shift键添加条件,而是在开始拖动节点事件时阻止触发缩放功能:

    var drag = force.drag()
        .on("dragstart", function (d) {
            d3.event.sourceEvent.stopPropagation();
        });

此处更新了jsfiddle: https://jsfiddle.net/IMykytiv/nsxL8c52/2/

希望它对任何人都有用:)