从JSON字符串而不是JSON文件中呈现D3图形

17

我试图在我的Rails应用程序中呈现以下系统树图:

http://bl.ocks.org/mbostock/4063570

我有一个模型,其中有很多属性,但我想手动嵌套这些属性,并仅使用字符串插值来构建自己的JSON字符串,然后直接将其传递给d3。

以下是我的代码:

    <%= javascript_tag do %>
        var width = 960,
        height = 2200;

        var cluster = d3.layout.cluster()
        .size([height, width - 160]);

        var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });

        var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(40,0)");

        **d3.json("/assets/flare.json", function(root) {**
        var nodes = cluster.nodes(root),
        links = cluster.links(nodes);

        var link = svg.selectAll(".link")
        .data(links)
        .enter().append("path")
        .attr("class", "link")
        .attr("d", diagonal);

        var node = svg.selectAll(".node")
        .data(nodes)
        .enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

        node.append("circle")
        .attr("r", 4.5);

        node.append("text")
        .attr("dx", function(d) { return d.children ? -8 : 8; })
        .attr("dy", 3)
        .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
        .text(function(d) { return d.name; });
        });

        d3.select(self.frameElement).style("height", height + "px");
    <% end %>

这是我的(未压缩的)JSON字符串:

var mystring = '{
    "name": "Product",
    "properties": {
        "id": {
            "type": "number",
            "description": "Product identifier",
            "required": true
        },
        "name": {
            "type": "string",
            "description": "Name of the product",
            "required": true
        },
        "price": {
            "type": "number",
            "minimum": 0,
            "required": true
        },
        "tags": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "stock": {
            "type": "object",
            "properties": {
                "warehouse": {
                    "type": "number"
                },
                "retail": {
                    "type": "number"
                }
            }
        }
    }
}';

我尝试过的方法:

  1. 将JSON文件压缩成一行输入(无效)

  2. 在字符串上运行JSON.parse(mystring)

  3. 查看D3文档和搜索一种方法来修改以下函数,使其接受字符串而不是文件路径:

d3.json("/assets/flare.json", function(root) {
        var nodes = cluster.nodes(root),
        links = cluster.links(nodes);
2个回答

39

首先,让我们看看d3.json是做什么的。

d3.json("/assets/flare.json", function(root) {
    // code that uses the object 'root'
});

该代码从服务器加载文件/assets/flare.json,将其内容解释为JSON格式,并将结果对象作为匿名函数的root参数传递。

如果您已经有了一个JSON对象,则无需使用d3.json函数 - 您可以直接使用该对象。

var root = {
   "name": "flare",
   "children": [
     ...
   ]
};
// code that uses the object 'root'
如果对象表示为字符串,那么您可以使用JSON.parse来获取对象。
var myString = '{"name": "flare","children": [ ... ] }';
var root = JSON.parse(mystring);
// code that uses the object 'root'

其次,让我们来看看 d3.layout.cluster 对数据的期望。根据文档

...默认的children访问者假定每个输入数据都是一个带有子数组的对象...

换句话说,您的数据需要具有以下形式:

var mystring = '{
    "name": "Product",
    "children": [
        {
            "name": "id",
            "type": "number",
            "description": "Product identifier",
            "required": true
        },
        ...
        {
            "name": "stock",
            "type": "object",
            "children": [
                {
                    "name: "warehouse",
                    "type": "number"
                },
                {
                    "name": "retail",
                    "type": "number"
                }
            ]
        }
    ]
}

1
knolleary,感谢您的解释。这很有帮助,但我特别想知道的是:如何更改d3.json("/assets/flare.json", function(root) {行以允许本地字符串?d3.json的语法是:d3.json(url[, callback])。我想在我的字符串上运行匿名函数,而不是URL。 - Quincy Larson
6
Michael,你可以通过将d3.json(..)行删除来进行更改... 如果已经有了字符串,那么就不需要使用函数从URL加载内容,这就是d3.json所做的。目前在d3.json(..)调用中指定的匿名函数可以简单地使用你拥有的字符串显式调用。这就是我在答案的前半部分试图描述的内容。 - knolleary
我该如何加载一个JSON文件呢?它总是给我错误提示。 - Dev R
Dev R:建议您在 Stack Overflow 周围搜索,因为有很多针对您特定问题的答案。 - knolleary
2
你可以在这里查看:https://dev59.com/3Ggu5IYBdhLWcg3w_L3J - Saqib Mobeen

1

d3.json实际上需要URL作为参数,因此建议将数据管理委托给控制器(特别是如果将来需要从数据库加载数据),以简化事情:

  1. 在控制器中创建一个方法,该方法将打开文件并返回其内容:
class YourFlareController < ApplicationController
    def load
        @data = File.read("app/assets/json/flare.json")
        render :json => @data
    end
end
  1. 确保你在routes.rb文件中有一个路由

get "yourflare/load"

  1. 现在在你的javascript代码中,你可以简单地调用以下方法

d3.json("http://host/yourflare/load", function(root) {


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接