Render D3-график из строки JSON вместо файла JSON
Я пытаюсь сделать следующий Dendrogram из моего приложения 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 и и googling, чтобы изменить следующую функцию, чтобы принять строку вместо пути к файлу: d3.json( "/assets/flare.json", function (root) { var nodes = cluster.nodes(root), links = cluster.links(узлы);
Ответы
Ответ 1
Сначала давайте посмотрим, что делает 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
ожидает ваших данных. По документам:
... дочерний аксессуар по умолчанию предполагает, что каждый входной объект является объектом с дочерним массивом...
Другими словами, данные должны иметь форму:
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"
}
]
}
]
}
Ответ 2
d3.json фактически использует URL как аргумент, поэтому вместо того, чтобы указывать путь к файлу, я бы предложил делегировать управление данными контроллеру (особенно, если в будущем вам нужно будет загрузить его из БД) поэтому для упрощения вещей:
- Создайте в контроллере метод, который фактически откроет файл и вернет его содержимое:
class YourFlareController < ApplicationController
def load
@data = File.read("app/assets/json/flare.json")
render :json => @data
end
end
- Убедитесь, что у вас есть маршрут на ваших маршрутах. rb
получить "yourflare/load"
- И теперь в вашем javascript вы можете просто вызвать
d3.json("http://host/yourflare/load", function(root) {