2013-07-12 11 views
10

ich folgende Dendrogram von meiner Rails-Anwendung zu machen versuchen: http://bl.ocks.org/mbostock/4063570aus einer Reihe von JSON Render D3 Graph anstelle einer JSON-Datei

habe ich ein Modell mit vielen Attributen, aber ich mag Nest manuell Diese Attribute verwenden einfach die String-Interpolation, um eine eigene JSON-Zeichenfolge zu erstellen, und übergeben diese dann direkt an d3.

Hier ist mein Code:

<%= 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 %> 

Hier ist meine (unminified) JSON-String:

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" 
       } 
      } 
     } 
    } 
}'; 

Dinge, die ich versucht habe:

1) minifying die JSON, so dass es eingegeben ist als nur eine Zeile (kein Effekt)

2) Ausführen von JSON.parse (MyString) auf der Zeichenfolge

3) durch die D3-Dokumentation suchen und googlen für eine Möglichkeit, die folgende Funktion zu ändern, um eine Zeichenfolge anstelle eines Dateipfads zu akzeptieren: d3.json ("/ assets/flare.json", function (root) { var nodes = cluster.nodes (root), Links = cluster.links (Knoten);

Antwort

23

Lassen Sie uns zuerst sehen, was d3.json tut.

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

Diese Datei /assets/flare.json vom Server lädt, interpretiert den Inhalt als JSON und übergibt das resultierende Objekt als root Argument für die anonyme Funktion.

Wenn Sie bereits ein JSON-Objekt haben, müssen Sie nicht die Funktion d3.json verwenden - Sie können das Objekt einfach direkt verwenden.

var root = { 
    "name": "flare", 
    "children": [ 
    ... 
    ] 
}; 
// code that uses the object 'root' 

Wenn das Objekt als Zeichenfolge dargestellt wird, dann können Sie JSON.parse, um das Objekt zu erhalten:

var myString = '{"name": "flare","children": [ ... ] }'; 
var root = JSON.parse(mystring); 
// code that uses the object 'root' 

Zweitens kann bei welchen d3.layout.cluster erwarten Ihre Daten suchen. Wie pro the docs:

... das Standard Kinder Accessor übernimmt jedes Eingangsdatum ein Objekt mit einem Kind-Array ...

Mit anderen Worten: Sie Daten müssen von der Form sein:

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" 
       } 
      ] 
     } 
    ] 
} 
+0

knolleary, danke Sie für die Erklärung tion. Das ist hilfreich, aber was ich speziell suche ist: Wie ändere ich die d3.json ("/ assets/flare.json", function (root) {Zeile, um eine lokale Zeichenkette zu erlauben? D3.json's Syntax ist: d3.json (url [, callback]). Ich möchte die anonyme Funktion in meinem String statt einer URL ausführen. –

+4

Michael, Sie ändern die d3.json (..) Zeile, indem Sie loswerden ... if Sie haben bereits die Zeichenfolge, Sie müssen keine Funktion verwenden, um Inhalt von einer URL zu laden, was alles ist, was d3.json tut.Die anonyme Funktion, die derzeit im Aufruf von d3.json (..) angegeben ist, kann einfach explizit aufgerufen werden Mit der Zeichenfolge, die Sie haben. Das ist, was ich versuchte, in der ersten Hälfte meiner Antwort zu beschreiben. – knolleary

+0

Wie kann ich eine JSON-Datei stattdessen laden? es gibt immer Fehler für mich –

3

d3.Json nimmt URL tatsächlich als Argument, also würde ich, anstatt ihm den Pfad zur Datei zu geben, empfehlen, die Datenverwaltung an den Controller zu delegieren (besonders, wenn Sie ihn in Zukunft aus der DB laden müssten), um die Dinge zu vereinfachen:

  1. erstellen Sie eine Methode in Ihrem Controller, die tatsächlich die Datei öffnen würde und das Rück seinen Inhalt:
class YourFlareController < ApplicationController 
    def load 
     @data = File.read("app/assets/json/flare.json") 
     render :json => @data 
    end 
end 
  1. Achten Sie darauf, eine Route in der Routen haben .rb

get "yourflare/load"

  1. Und jetzt in Ihrem Javascript können Sie einfach anrufen

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

Verwandte Themen