我一般都是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
}
答案 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
最后一条评论是使用JSLint或JSHint等工具来验证您的代码。它会自动指出这样的问题。它有时可能过于严格,但它至少可以理解它所抱怨的学习经验。