2017-06-03 25 views
0

我从我的.html文件引用.js文件,并试图我SVG图表追加到特定的div的。不过,我得到在控制台下面的消息时,我打开HTML文件:SVG阵列不可用HTML页面

TypeError: svg[0] is undefined 

当我包括我的html和我的script.js代码沿脚本标签,我可以找到“SVG”阵列(和预期的饼图)从控制台。 [我使用这些数据在下面的stack.js结尾创建了forEach循环。]我知道stack.js代码的工作原理,因为它与我前几天发布的this question的代码相同。

我很好奇,为什么我不能让我的.html文件“看到”从我的js文件的阵列。有没有办法做到这一点,或者我错过了我应该使用d3的最佳做法?它与d3 being asynchronous有什么关系?

stack.html:

<!doctype html> 
<html> 
<head> 
    <meta charset="UTF-8"> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> 
    <script src="stack.js"></script> 
</head> 

<body> 
    <div id="pie1"></div> 
    <div id="pie2"></div> 
</body> 
</html> 

stack.js

var data = { 
    "data":[ 
     {"pie_one": { 
      "id": "pie1", 
      "results": [ 
       {"ratio": 0.04, "total": 7, "failures": 1}, 
       {"ratio": 0.04, "total": 8, "failures": 0}, 
       {"ratio": 0.04, "total": 9001, "failures": 0} 
      ]} 
     }, 
     {"pie_two": { 
      "id": "pie2", 
      "results": [ 
       {"ratio": 0.04, "total": 10, "failures": 0}, 
       {"ratio": 0.04, "total": 11, "failures": 1}, 
       {"ratio": 0.04, "total": 12, "failures": 1} 
      ]} 
     } 
    ] 
}; 

var width = 300, 
    height = 300, 
    radius = Math.min(width, height)/2; 

var arc = d3.svg.arc() 
    .outerRadius(radius) 
    .innerRadius(radius - (radius/2)); 

var pie = d3.layout.pie() 
    .sort(null) 
    .value(function(d) { return d.ratio; }); 

var svg = d3.select("body").selectAll("svg") 
    .data(data.data) 
    .enter() 
    .append("svg") 
    .attr("width", width) 
    .attr("height", height) 
    .append("g") 
    .attr("transform", "translate(" + width/2 + "," + height/2 + ")"); 

svg[0].forEach(function(pie) { 
     var div = document.getElementById(pie.__data__.id); 
     div.innerHTML = pie; 
    }); 

var g = svg.selectAll(".arc") 
    .data(function(d,i) { return pie(d["pie"+(i+1)].results) }) 
    .enter().append("g") 
    .attr("class", "arc") 

    g.append("path") 
    .attr("d", arc) 
    .style("fill", function(d) { return (d.data.failures > 0) ? "#d63535" : "#22c12d"; }); 

window.onload = function() { 
    svg[0].forEach(function(pie) { 
     var div = document.getElementById(pie.__data__.id); 
     div.innerHTML = pie; 
    }); 
}; 
+0

为什么你在forEach中使用'svg [0]',是不是'svg'? –

+0

@AhmedMasud这里是控制台对于svg :(阵列[数组[2]])和svg [0]的结果:(阵列[,]) – Drew

+1

您正试图访问DOM元素你的DOM是建立的。你应该把所有的代码移到你的onload函数中。但绝对是它处理任何文档相关对象的部分。 – clockwatcher

回答

2

,你不能引用您的SVG的原因[0] is--正如我在提到我评论 - 因为你正在尝试在DOM加载之前做些事情。将你的代码移动到window.onload中可以解决这个特定的错误,但是你在尝试做事情时会遇到其他问题。

下面是一个工作示例,更你想要做什么。您应该使用d3的功能将图表嵌入您想要的位置。而不是把它们粘在身体里,然后试着移动它们。

stack.js

var data = { 
    "data":[ 
     { 
      "id": "pie1", 
      "results": [ 
       {"ratio": 0.04, "total": 7, "failures": 1}, 
       {"ratio": 0.04, "total": 8, "failures": 0}, 
       {"ratio": 0.04, "total": 9001, "failures": 0} 
      ] 
     }, 
     { 
      "id": "pie2", 
      "results": [ 
       {"ratio": 0.04, "total": 10, "failures": 0}, 
       {"ratio": 0.04, "total": 11, "failures": 1}, 
       {"ratio": 0.04, "total": 12, "failures": 1} 
      ] 
     } 
    ] 
}; 

window.onload = function() { 

var width = 300, 
    height = 300, 
    radius = Math.min(width, height)/2; 

var arc = d3.svg.arc() 
    .outerRadius(radius) 
    .innerRadius(radius - (radius/2)); 

var pie = d3.layout.pie() 
    .sort(null) 
    .value(function(d) { return d.ratio; }); 

var svg = d3.select("body") 
    .selectAll("div") 
    .data(data.data, function(d) { return d ? d.id : this.id }) 
    .append("svg") 
    .attr("width", width) 
    .attr("height", height) 
    .append("g") 
    .attr("transform", "translate(" + width/2 + "," + height/2 + ")"); 

var g = svg.selectAll(".arc") 
    .data(function(d) { return pie(d.results) }) 
    .enter().append("g") 
    .attr("class", "arc") 
    .append("path") 
    .attr("d", arc) 
    .style("fill", function(d) { return (d.data.failures > 0) ? "#d63535" : "#22c12d"; }); 

}; 

的关键,让你想让他们是在数据绑定呼叫的第二个参数的图表。

.selectAll("div") 
    .data(data.data, function(d) { return d ? d.id : this.id }) 

rows--其中那些密钥匹配,D3结合该特定数据行,用以对数据元素进行上述生成用于两个元件和数据的密钥值。

我也改变了你的数据结构一点点,因为你正在做独特的按键事识别您的对象的方式使得它很难与数据D3的思想工作。如果出于某种原因无法更改数据结构,那么我会建议一个中间函数来将数据重塑为更易于使用的内容。上一个问题中的另一张海报也对您的数据结构进行了评论。

您的stack.html保持不变。

<!doctype html> 
<html> 
<head> 
    <meta charset="UTF-8"> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> 
    <script src="stack.js"></script> 
</head> 

<body> 
    <div id="pie1"></div> 
    <div id="pie2"></div> 
</body> 
</html>