使用d3,Firefox上的“Tick not defined”错误

时间:2013-08-08 15:10:43

标签: firefox cross-browser d3.js

我一般都是d3和网络编程的新手。我已经根据https://gist.github.com/mbostock/1153292整理了一个力布局图。该图在Safari,Chrome和Opera中运行良好(我还没有检查过IE)。但是当我尝试在Firefox中使用它时,我收到错误“Tick is not defined”。我正在使用Firefox 12。

对此的任何建议都将非常感激 谢谢, 克莱尔

(代码是一个js脚本文件,在鼠标点击时触发,力布局部分在下面。)。

d3.csv("data/sharing.csv?r1",  function(error, data) {
                    dataset = data
                    var nodes = {};

        dataset.forEach(function(link) {
        link.source = nodes[link.source] || (nodes[link.source] =    {name:link.source});
        link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
        });


        var w = 500;
        var h = 600;

                         var force = d3.layout.force()
            .nodes(d3.values(nodes))
            .links(dataset)
            .size([w-10,h-10]) 
            .linkDistance(60) 
            .charge(-375) 
            .on("tick", tick)
            .start();

        //Draw svg canvas
        var svg = d3.select("#svgContainer").append("svg").attr("id", "viz").attr("width", w).attr("height", h)

        // Create arrowheads
        svg.append("svg:defs").selectAll("marker")
            .data(["end-arrow"])
            .enter()
            .append("svg:marker")
            .attr("id", String)
            .attr("viewBox", "0 -5 10 10")
            .attr("refX", 15)
            .attr("refY", -1.5)
            .attr("markerWidth", 6)
            .attr("markerHeight", 6)
            .attr("orient", "auto")
            .attr("fill", "black") 
            .append("svg:path")
            .attr("d", "M0,-5L10,0L0,5");

        //Add links between the nodes and draw arrowhead at end of it.
        var path = svg.append("svg:g").selectAll("path")
            .data(force.links())
            .enter()
            .append("svg:path")
            .attr("stroke-width",2)
                        .attr("stroke", "black")
            .attr("fill","none")
            .attr("marker-end", "url(#end-arrow)");

        //Draw circles for nodes
        var circle = svg.append("svg:g").selectAll("circle")
            .data(force.nodes())
            .enter()
            .append("svg:circle")
            .attr("r", 6)
            .attr("fill", "white")
            .attr("stroke", "black")
            .call(force.drag)
            .on("mouseover", fade(.1))
            .on("mouseout", fade(1))

        //Label the nodes/circles
        var text = svg.append("svg:g").selectAll("g")
            .data(force.nodes())
            .enter()
            .append("svg:g")

        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .text(function(d) { return d.name; })

        function tick() {
          path.attr("d", function(d) {
            var dx = d.target.x - d.source.x,
                dy = d.target.y - d.source.y,
                dr = Math.sqrt(dx * dx + dy * dy);
            return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
          });

          circle.attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
          });

          text.attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
          });
        }


=============REPLY TO COMMENT == FULL SCRIPT INCLUDING CALL TO CSV===

//If sharing button is clicked, load sharing data
d3.select("#sharing").on("click", function() {
d3.csv("data/sharing.csv?r1",  function(error, data) {
if (error)  
{//If error is not null,(i.e : something goes wrong), log the error.                            
window.console.log(error);      
} 
else 
{//If file loaded correctly, log the data to the console.   
dataset = data
window.console.log(dataset) 
color = getColor()
vizType = "force";

//Hide date fields/buttons as they are not applicable 
d3.select("#instructions").classed("hidden", true);
d3.select("#instructions2").classed("hidden", false);
d3.select("#startLabel").classed("hidden", true);   
d3.select("#startDate").classed("hidden", true);    
d3.select("#endLabel").classed("hidden", true); 
d3.select("#endDate").classed("hidden", true);  
d3.select("#removeFilter").classed("hidden", true); 
d3.select("#sharing").classed("hidden", true);
d3.select("#showData").classed("hidden", false);
d3.select("#showData").attr("value", "Back to Circles Vizualization");
d3.select("#tipsData").classed("hidden", true); 
d3.select("#ncpData").classed("hidden", true);      
d3.select("#tipsNCPData").classed("hidden", true);
d3.select("#tipsLabel").classed("hidden", true);    
d3.select("#ncpLabel").classed("hidden", true);     
d3.select("#tipsNCPLabel").classed("hidden", true);  

//Clear the previous viz and data
d3.select("#viz").remove();
d3.select("#stageTable").remove();
d3.select("#userTable").remove();

//Gets a count of sender records/source and stage/type          
var senderCount = getSortingCount(dataset,"Sender");
var stageCount = getSortingCount(dataset,"Stage");

//create tables summarising results
var summarySenderTable = tabulate(senderCount, ["Shared", "Sender"], vizType);  
var summaryStageTable = tabulate(stageCount, ["Shared", "Stage"], vizType);

var nodes = {};

// For each datapoint, check if a node exists already, if not create a new one. 
dataset.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] ={name: link.source});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});

//Set the width and height for the svg, that will display the viz
var w = 500;
var h = 600;

var force = d3.layout.force()
          .nodes(d3.values(nodes))
          .links(dataset)
          .size([w-10,h-10])  
      .linkDistance(60) 
      .charge(-375) 
      .on("tick", tick)
      .start();

//Draw svg
var svg =    d3.select("#svgContainer").append("svg")
.attr("id","viz").attr("width",w).attr("height", h)

// Create arrowheads
svg.append("svg:defs").selectAll("marker")
          .data(["end-arrow"])
          .enter().append("svg:marker")
          .attr("id", String)
          .attr("viewBox", "0 -5 10 10")
          .attr("refX", 15)
          .attr("refY", -1.5)
          .attr("markerWidth", 6)
          .attr("markerHeight", 6)
          .attr("orient", "auto")
          .attr("fill", "black") 
          .append("svg:path")
          .attr("d", "M0,-5L10,0L0,5");

//Add links between the nodes and draw arrowhead at end of it.
var path = svg.append("svg:g").selectAll("path")
     .data(force.links())
     .enter()
     .append("svg:path")
     .attr("stroke-width",2)
     .attr("stroke", function(d){return color(d.ScreenName)})  
     .attr("fill","none")
     .attr("marker-end", "url(#end-arrow)");

//Draw circles for nodes
var circle = svg.append("svg:g").selectAll("circle")
       .data(force.nodes())
           .enter()
           .append("svg:circle")
           .attr("r", 6)
       .attr("fill", "white")
       .attr("stroke", "black")
       .call(force.drag)
       .on("mouseover", fade(.1))
       .on("mouseout", fade(1))

//Label nodes/circles
var text = svg.append("svg:g").selectAll("g")
          .data(force.nodes())
      .enter()
      .append("svg:g")  
       text.append("svg:text")
      .attr("x", 8)
      .attr("y", ".31em")
      .text(function(d) { return d.name; })  

//Set radius for arrows and applies transform 
function tick() {
   path.attr("d", function(d) {
   var dx = d.target.x - d.source.x,
       dy = d.target.y - d.source.y,
       dr = Math.sqrt(dx * dx + dy * dy);
   return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " +   d.target.x + "," + d.target.y;
   });

   circle.attr("transform", function(d) {
   return "translate(" + d.x + "," + d.y + ")";
   });

   text.attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
   });
}   
//Allow for filter by row on stageTable
d3.select("#stage").select("#stageTable").selectAll("tr")
          .on("click", function(d){
          d3.select(this)
          var rowText = this.childNodes[1].innerHTML
          var svg = d3.select("#svgContainer").select("svg")
          var path = svg.selectAll("path")
                .style ("opacity", 1)
                .transition()
                    .duration(250)
                .style ("opacity", function(d){
          if(d.ScreenName == rowText){  
                      d3.selectAll("marker path").transition().style("stroke-opacity", 1);
          return fade(1)    
          }
         else{
        d3.selectAll("marker path").transition().style("stroke-opacity", 0.1);
          return 0.1
          })
        d3.select("#removeFilter").classed("hidden", false);                
          })

//Checks what links are connected to which(used for mouseover) 
var linkedByIndex = {};
dataset.forEach(function(d) {linkedByIndex[d.source.index + "," + d.target.index] = 1;});

function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] ||     a.index == b.index;
}
                                                        //Fades in/out circles and arrows on mouseover.
function fade(opacity) {
return function(d) {
circle.style("stroke-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
 });
path.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
 });

};
}       

}   
})

})

Accessor for colour
function getColor(){
return color
}                           

1 个答案:

答案 0 :(得分:1)

查看整个源代码有助于澄清事情。最顶层有一个if / else语句来检查错误。其余代码都在else块中。这就是造成这个问题的原因。

函数声明(例如你的案例中的tick())在条件块中定义时具有特定于浏览器的怪异行为。 Here's a pretty good write-up解释了函数声明函数表达式与错误定义和不一致支持的函数语句之间的区别(这是什么你无意中创造了如此多的代码生活在一个else块中。)

如果你从else块中提取代码,我认为这种行为在浏览器中应该更容易预测。

通常,创建巨大的长条件块并不是一种好的编程习惯。它不仅引入了这些类型错误的可能性,而且很难阅读和理解。同样的事情也适用于非常深层的嵌套条件。

尽量保持条件相当紧密,以使条件块内的代码直接对应条件本身的含义。你应该能够大声读出条件的意图和阻止内容,它们应该在一起有意义。与条件无关的代码应尽可能位于包含它的函数的顶层。您可以通过将代码分解为有意义的函数并控制条件来提高可读性。

在上面的示例中,您可以执行以下操作:

if (error) {                            
    window.console.log(error);      
} 
else {
    window.console.log(dataset);
}

dataset = data 
color = getColor()
vizType = "force";
...
... rest of code

最后一条评论是使用JSLintJSHint等工具来验证您的代码。它会自动指出这样的问题。它有时可能过于严格,但它至少可以理解它所抱怨的学习经验。