【问题标题】:SVG array not available to HTML pageSVG 数组不适用于 HTML 页面
【发布时间】:2017-06-03 20:27:09
【问题描述】:

我正在从我的 .html 文件中引用一个 .js 文件,并尝试将我的 SVG 图表附加到特定的 div 中。但是,当我打开 html 文件时,我在控制台中收到以下消息:

TypeError: svg[0] is undefined

当我在我的 html 中包含 script 标记以及我的 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;
    });
};

【问题讨论】:

  • 你为什么在你的forEach中使用svg[0],不应该是svg吗?
  • @AhmedMasud 这是来自控制台的结果 svg: (Array [ Array[2] ])... 和 svg[0]: (Array [ , ] )
  • 您正在尝试在构建 DOM 之前访问 DOM 元素。您应该将几乎所有这些代码移到您的 onload 函数中。但绝对是处理任何文档相关对象的部分。
  • @clockwatcher 将代码移动到document.onload = function() { my code } 似乎没有奏效。不过,我认为您正在做一些事情,我会研究 onload 的使用情况。

标签: javascript html d3.js svg pie-chart


【解决方案1】:

你不能引用你的 svg[0] 的原因是——正如我在评论中提到的——因为你试图在加载 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 })

以上代码为元素和数据行生成一个键值——当这些键匹配时,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>

【讨论】:

    猜你喜欢
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 2021-02-23
    • 1970-01-01
    • 2021-08-01
    • 2015-02-18
    • 1970-01-01
    相关资源
    最近更新 更多