2017-04-25 5 views
1

Am machen ein Diagramm mit Daten aus einer API und setzen diese in einem Diagramm (https://bl.ocks.org/mbostock/4062045) aufgenommen zu machen versuchen - Kraft-Directed GraphWie ein Diagramm auf VueJS

Allerdings bin ich nicht sicher, wie man dies getan einge VueJs oder wenn es ein einfacheres Werkzeug dafür gibt?

D3 Force-Directed Graph scheint ein bisschen kompliziert, vielleicht gibt es bereits eine Bibliothek, die das out of the Box tut?

+0

Herr Sie gehen https://www.npmjs.com/package/vue-d3 –

+0

werfen Sie einen Blick in https://github.com/johnnynotsolucky/samples/tree/master/vuejs-d3 können Sie mehr Demos suchen auf https://github.com/vuejs/awesome-vue – Ethaan

Antwort

2

Das erwähnte vue-d3 Paket aus dem Kommentar fügt nur D3 zum Vue-Prototyp hinzu, so dass es mit this.$d3 zugänglich ist.

Ich habe dieses Paket getestet, aber es funktionierte nicht mit meiner D3-Version. Sieht aus wie ein Gehäuseproblem (D3 statt d3). Also habe ich den Prototyp manuell hinzugefügt.

Ich weiß nicht, ob es eine einfachere Bibliothek zum Erstellen eines Force-Diagramms gibt, aber bitte sehen Sie sich die folgende Demo oder diese fiddle an.

Ich habe das Beispiel von Ihrem Link geändert, um eine Kraft gerichtete Grafik zu erstellen. Die Demo funktioniert, aber wie du schon erwähnt hast, ist es ziemlich kompliziert. Auch die Bindung von SVG an das Vue.js-Modell konnte verbessert werden. Aber ich konnte keinen besseren Weg finden, es zu tun.

Zum Beispiel funktioniert das Hinzufügen eines neuen Knotens beim Klicken nicht mit dem Hinzufügen eines neuen Knotens zum Array, aber dies sollte das Ziel für eine Vue.js-Komponente sein. Der SVG-Graph sollte automatisch aktualisiert werden, sobald sich die Daten ändern.

Momentan werden Knoten und Verknüpfungen in Vue.js nicht in der Komponente verwendet, da ich nicht weiß, wie die Aktualisierung des Diagramms hinzugefügt werden kann.

Wenn Sie herausgefunden haben, wie Sie die Aktualisierung mit den Modelldaten hinzufügen können, lassen Sie es mich wissen. Das Aktualisieren des gesamten Diagramms ist ziemlich einfach, indem Sie das SVG löschen und neu erstellen. (Siehe Reload-Button)

// https://unpkg.com/[email protected] --> only adds d3 to Vue.prototype but it wasn't working as expected (d3 is lower case) 
 
Vue.prototype.$d3 = d3; 
 
const URL = 'https://demo5147591.mockable.io/miserables'; // data copied from below link because of jsonp support 
 

 
//'https://bl.ocks.org/mbostock/raw/4062045/5916d145c8c048a6e3086915a6be464467391c62/miserables.json'; 
 
//console.log(window.d3); 
 
const d3ForceGraph = { 
 
    template: ` 
 
    <div> 
 
    {{mousePosition}} 
 
    <button @click="reload">reload</button> 
 
    <svg width="600" height="600" 
 
    \t @mousemove="onMouseMove($event)"></svg> 
 
    </div> 
 
    `, 
 
    data() { 
 
    return { 
 
     nodes: [], 
 
     links: [], 
 
     simulation: undefined, 
 
     mousePosition: { 
 
     x: 0, 
 
     y: 0 
 
     } 
 
    } 
 
    }, 
 
    mounted() { 
 
    this.loadData(); // initially load json 
 
    }, 
 
    methods: { 
 
    // load data 
 
    loadData() { 
 
    \t \t this.$svg = $(this.$el).find('svg'); 
 
     let svg = this.$d3.select(this.$svg.get(0)), //this.$d3.select("svg"), 
 
      width = +svg.attr("width"), 
 
      height = +svg.attr("height"); 
 
     //console.log($(this.$el).find('svg').get(0)); 
 

 
     this.simulation = this.$d3.forceSimulation() 
 
      .force("link", this.$d3.forceLink().id(function(d) { 
 
      return d.id; 
 
      })) 
 
      .force("charge", this.$d3.forceManyBody()) 
 
      .force("center", this.$d3.forceCenter(width/2, height/2)); 
 
     let color = this.$d3.scaleOrdinal(this.$d3.schemeCategory20); 
 
     $.getJSON(URL, (graph) => { 
 
      //d3.json("miserables.json", function(error, graph) { // already loaded 
 
      //if (error) throw error; // needs to be implemented differently 
 
      let nodes = graph.nodes; 
 
      let links = graph.links; 
 
      
 
      let link = svg.append("g") 
 
      .attr("class", "links") 
 
      .selectAll("line") 
 
      .data(links) //graph.links) 
 
      .enter().append("line") 
 
      .attr("stroke-width", function(d) { 
 
       return Math.sqrt(d.value); 
 
      }); 
 

 
      let node = svg.append("g") 
 
      .attr("class", "nodes") 
 
      .selectAll("circle") 
 
      .data(nodes) //graph.nodes) 
 
      .enter().append("circle") 
 
      .attr("r", 5) 
 
      .attr("fill", function(d) { 
 
       return color(d.group); 
 
      }) 
 
      .call(this.$d3.drag() 
 
       .on("start", this.dragstarted) 
 
       .on("drag", this.dragged) 
 
       .on("end", this.dragended)); 
 

 
      node.append("title") 
 
      .text(function(d) { 
 
       return d.id; 
 
      }); 
 

 
      this.simulation 
 
      .nodes(graph.nodes) 
 
      .on("tick", ticked); 
 

 
      this.simulation.force("link") 
 
      .links(links); //graph.links); 
 

 
      function ticked() { 
 
      link 
 
       .attr("x1", function(d) { 
 
       return d.source.x; 
 
       }) 
 
       .attr("y1", function(d) { 
 
       return d.source.y; 
 
       }) 
 
       .attr("x2", function(d) { 
 
       return d.target.x; 
 
       }) 
 
       .attr("y2", function(d) { 
 
       return d.target.y; 
 
       }); 
 

 
      node 
 
       .attr("cx", function(d) { 
 
       return d.x; 
 
       }) 
 
       .attr("cy", function(d) { 
 
       return d.y; 
 
       }); 
 
      } 
 
     }) 
 
     }, 
 
     reload() { 
 
     //console.log('reloading...'); 
 
     this.$svg.empty(); // clear svg --> easiest way to re-create the force graph. 
 
     this.loadData(); 
 
     }, 
 
     // mouse events 
 
     onMouseMove(evt) { 
 
     //console.log(evt, this) 
 
     this.mousePosition = { 
 
      x: evt.clientX, 
 
      y: evt.clientY 
 
     } 
 
     }, 
 
     // drag event handlers 
 
     dragstarted(d) { 
 
     if (!this.$d3.event.active) this.simulation.alphaTarget(0.3).restart(); 
 
     d.fx = d.x; 
 
     d.fy = d.y; 
 
     }, 
 
     dragged(d) { 
 
     d.fx = this.$d3.event.x; 
 
     d.fy = this.$d3.event.y; 
 
     }, 
 
     dragended(d) { 
 
     if (!this.$d3.event.active) this.simulation.alphaTarget(0); 
 
     d.fx = null; 
 
     d.fy = null; 
 
     } 
 
    } 
 
}; 
 

 
new Vue({ 
 
    el: '#app', 
 
    data() { 
 
    return {} 
 
    }, 
 
    components: { 
 
    d3ForceGraph 
 
    } 
 
});
.links line { 
 
    stroke: #999; 
 
    stroke-opacity: 0.6; 
 
} 
 

 
.nodes circle { 
 
    stroke: #fff; 
 
    stroke-width: 1.5px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script> 
 

 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="app"> 
 
    <d3-force-graph></d3-force-graph> 
 
</div>

1

ich eine weitere Frage auf vue + d3 beantwortet durch ein Beispiel eines d3 force graph with vue.js bereitstellt.

d3.js ist jetzt in kleine Module aufgeteilt und spezifische Berechnungen sind in kleinen Komponenten wie d3-force isoliert. SVG kann wie jede andere HTML-Struktur in einer Komponentenvorlage gezeichnet werden.