d3无法读取属性" on"未定义的

时间:2016-03-15 11:23:44

标签: javascript html d3.js svg

我在多个SO帖子中多次看到过这个问题,虽然发布类似于重复的内容感觉不对,但这个错误似乎出现了很多不同的原因,因此每个问题都与持续。所以我们在这里解决我的问题:

这是我的代码;

window.onload = function () {

    var width = 750,
        height = 750,
        counter = 0;

    var force = d3.layout.force()
        .size([width, height]);

    d3.csv("Data/BubbleData.csv", function (error, links) {

        var X = d3.scale.linear()
            .domain([0, width])
            .range([0, width]);

        var Y = d3.scale.linear()
            .domain([0, height])
            .range([height, 0]);

        var zoom = d3.behavior.zoom()
            .x(X)
            .y(Y)
            .scaleExtent([1, 10])
            .on("zoom", zoomed);

        //handle zooming
        function zoomed() {
            circles.attr("transform", transform);
        }

        function transform(d) {
            return "translate(" + X(d[0]) + "," + Y(d[1]) + ")";
        };

        var svg = d3.select("#GraphDiv")
                    .append("svg")
                        .attr("width", width)
                        .attr("height", height)
                        .append("g")
                        .call(d3.behavior.zoom().x(X).y(Y).scaleExtent([1, 10]).on("zoom", zoom))
                        .on("dblclick.zoom", null);


        var rect = svg.append("rect")
            .attr("width", width)
            .attr("height", height)
            .style("fill", "none")
            .style("pointer-events", "all");

        var color = d3.scale.category10();
        var edges = [],
            nodesByNames = {};

        //create the nodes
        links.forEach(function (link) {
            link.App_No = nodeByName(link.App_No);
            link.Server_No = nodeByName(link.Server_No);

            edges.push({ source: link.App_No, target: link.Server_No })
        });

        var nodes = d3.values(nodesByNames);

        //create container for all to go in
        var container = svg.append("g")
            .attr("class","container");

        //create the links
        var link = container.append("g")
                    .attr("class","LineGroup")
            .selectAll(".link")
                .data(edges)
            .enter().append("line")
            .attr("class", "link");

        //define mouse behaviour for nodes
        var drag = force.drag()
            .on("dragstart", function (d) { d3.select(this).select("circle").classed("fixed", d.fixed = true); });

        //create the nodes circles
        var node = container.append("g")
                .attr("class","circleGroup")
            .selectAll(".node")
                .data(nodes)
            .enter().append("g")
                .attr("class", "node")
            .call(drag);

        var circles = node.append("circle")
            .attr("r", 10)
            .attr("class", "circle")
            .attr("fill", function (d) { return color(d.group); })
            .on("dblclick", function (d) { d3.select(this).classed("fixed", d.fixed = false); });

        var labels = node.append("text")
            .attr("x", 12)
            .attr("y", ".35em")
            .text(function (d) { return d.Name; });

        force
            .nodes(nodes)
            .links(edges)
            .linkDistance(50)
            .charge(-100)
            .size([width, height])
            .on("tick", tick)
            .start();

        //draws the lines
        function tick() {
            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("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });

        }

        function nodeByName(name) {
            var groupNo;
            switch (name.substring(0, 1)) {
                case "A":
                    groupNo = 1;
                    break;
                case "S":
                    groupNo = 2;
                    break;
                default:
                    groupNo = 0;
            }
            return nodesByNames[name] || (nodesByNames[name] = { Name: name, group: groupNo });
        }
    });
};

我的数据:

App_Name,App_No,Server_Name,Server_No
App_01,A1,Server_01,S1
App_01,A1,Server_02,S2
App_01,A1,Server_03,S3
App_01,A1,Server_04,S4
App_02,A2,Server_03,S3
App_02,A2,Server_04,S4
App_02,A2,Server_05,S5
App_03,A3,Server_05,S5
App_03,A3,Server_06,S6
App_03,A3,Server_07,S7

我正在尝试将这两个示例(herehere)结合起来,以便在节点上具有拖动行为,同时能够进行语义缩放。我必须禁用缩放dblclick行为(请参阅代码),否则clickdragfixun-fix行为都可以正常运行,但是我在"cannot read property "on" of undefined"库本身内发生d3错误(chrome中的调试器显示它中断的行号(第1321行))。

我的代码是否正确?我是否在正确的位置(svg var)应用缩放行为?我是否将转换应用于正确的组(在这种情况下是圈组?)

编辑:错误发生在d3.js库的第1321行。它说" g"一片空白。我出于某种原因可能只是有一个错误的d3库吗?

2 个答案:

答案 0 :(得分:1)

我使用CSV转JSON转换器来转换数据,这样我就可以创建一个小提琴。所以这里:

在这个答案的帮助下:semantic zooming of force directed graph in d3

这个JSFiddle:http://jsfiddle.net/cSn6w/6/

我已经解决了这个问题。基本上你想拖动节点并保持它们就位,你已经解决了吗?你想放大但保持节点大小相同? (语义缩放)。

因此,当您进行缩放时,您需要更改节点的大小,但要获得正确的大小,您需要获得比例因子并获得您需要知道翻译因子的位置。所以创建像这样的变量:

var scaleFactor = 1;
var translation = [0,0];

这些将被覆盖。

现在缩放时你想要更新这些:

var zoom = d3.behavior.zoom()
                .scaleExtent([0.1,10])
        //allow 10 times zoom in or out
                .on("zoom", zoomed);

function zoomed() {
   // console.log("zoom", d3.event.translate, d3.event.scale);
    scaleFactor = d3.event.scale;
    translation = d3.event.translate;

    tick(); //update positions
}

zoomed函数更新比例并翻译我们之前声明的变量。然后调用tick来更新节点和链接的位置以及节点的大小。更新了刻度函数:

//draws the lines
function tick() {
  link.attr("x1", function(d) {
      return translation[0] + scaleFactor * d.source.x;
    })
    .attr("y1", function(d) {
      return translation[1] + scaleFactor * d.source.y;
    })
    .attr("x2", function(d) {
      return translation[0] + scaleFactor * d.target.x;
    })
    .attr("y2", function(d) {
      return translation[1] + scaleFactor * d.target.y;
    });

  node.attr("cx", function(d) {
      //console.log(translation[0] + scaleFactor*d.x)
      return translation[0] + scaleFactor * d.x;
    })
    .attr("cy", function(d) {
      return translation[1] + scaleFactor * d.y;
    });

  node.attr("transform", function(d) {
    return "translate(" + (translation[0] + scaleFactor * d.x) + "," + (translation[1] + scaleFactor * d.y) + ")";
  });
}

这里你必须要了解的是,当调用此函数时,它使用translate和scale变量来为节点提供正确的位置。

现在这样可以正常工作,但是由于你没有实现规模并在那里进行翻译,因此阻力不大。我已经改变了拖动功能:

var drag = force.drag()
  .origin(function(d) {
    return d;
  })
  .on("dragstart", dragstarted)
  .on("drag", dragged)
  .on("dragend", dragended);



function dragstarted(d) {
  console.log('start')
  d3.event.sourceEvent.stopPropagation();
  d3.select(this).classed("dragging", true);
}

function dragged(d) {
  console.log('dragged')
  d3.select(this).attr("cx", d.x = d3.event.x + translation[0]).attr("cy", d.y = d3.event.y + translation[1]);
}

function dragended(d) {
  console.log('dragended')
  d.fixed = true;
  d3.select(this).classed("dragging", false);
}

注意在dragged函数中我使用scale和translate来获得正确的位置。线d3.event.sourceEvent.stopPropagation();也会停止闪烁,如果你拿出来就可以看出我的意思。

这是更新的小提琴:https://jsfiddle.net/reko91/rw0o9vxh/2/

这能解决您的问题吗?

PS

你没有工作,因为没有d [0]和d [1]的值。

答案 1 :(得分:-1)

这一行怎么样:

 .call(
     d3.behavior.zoom()
          .x(X)
          .y(Y)
          .scaleExtent([1, 10])
          .on("zoom", zoom)
  )
 .on("dblclick.zoom", null);

您可能想将dbliclick.zoom放在括号中。

否则,因为使用回调来加载csv,可能会吞下您的文件错误。

如果不是我链接的代码使用中间变量和debogguer工具来检查你是否有某个未定义的返回。 Builder模式很适合语法,但不适合调试。