如何在VueJS上制作图表

时间:2017-04-25 18:15:50

标签: node.js graph vue.js

尝试使用从API接收的数据创建图表并将其放在图表上(https://bl.ocks.org/mbostock/4062045) - 强制导向图

但是我不确定如何在VueJ上完成这项工作,或者是否有更简单的工具来执行此操作?

D3 Force-Directed Graph似乎有点复杂,也许有一个库可以开箱即用吗?

3 个答案:

答案 0 :(得分:2)

评论中提到的vue-d3软件包只是将D3添加到Vue原型中,因此可以使用this.$d3访问它。

我已经测试过该软件包,但它不适用于我的D3版本。看起来像套管问题(D3而不是d3)。所以我手动添加了原型。

我不知道是否有更容易创建力图的库,但请查看下面的演示或fiddle

我已经修改了链接中的示例以创建力导向图。该演示正在运行,但正如您所提到的,它非常复杂。 还可以改进从SVG到Vue.js模型的绑定。但我找不到更好的方法来做到这一点。

例如,在单击时添加新节点不能仅仅向阵列添加新节点,但这应该是Vue.js组件的目标。一旦数据发生变化,SVG图表就会自动更新。

目前,Vue.js中的节点和链接未在组件中使用,因为我不知道如何添加图表的更新。

如果您想出如何使用模型数据添加更新,请告诉我们。通过删除SVG并重新创建它,刷新整个图表非常容易。 (见重新加载按钮)

// https://unpkg.com/vue-d3@0.1.0 --> 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" 
    	@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() {
    		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 :(得分:1)

我通过提供一个d3 force graph with vue.js的例子来回答关于vue + d3的另一个问题。

d3.js现在拆分为小模块,特定计算被隔离在像d3-force这样的小组件中。 SVG可以像任何其他HTML结构一样在组件模板中绘制。

答案 2 :(得分:0)

您可以使用vue-d3-network

npm install vue-d3-network 参见this fiddle

html: ```

    <head>
       <script type="text/javascript" src="https://unpkg.com/vue"> 
       </script>
       <link rel="stylesheet" type="text/css" href="https://rawgit.com/emiliorizzo/vue-d3-network/master/dist/vue-d3-network.css">
       <script type="text/javascript" src="https://rawgit.com/emiliorizzo/vue-d3-network/master/dist/vue-d3-network.umd.js"></script>
    </head>

  <body>
    <div id="app">
    <d3-network :net-nodes="nodes" :net-links="links" :options="options">
    </d3-network>
  </div>
  </body>

```

javascript: ``

var D3Network = window['vue-d3-network']
new Vue({
  el: '#app',
  components: {
    D3Network
  },
  data () {
    return {
      nodes: [
        { id: 1, name: 'my node 1' },
        { id: 2, name: 'my node 2' },
        { id: 3, _color:'orange' },
        { id: 4 },
        { id: 5 },
        { id: 6 },
        { id: 7 },
        { id: 8 },
        { id: 9 }
      ],
      links: [
        { sid: 1, tid: 2, _color:'red' },
        { sid: 2, tid: 8, _color:'f0f' },
        { sid: 3, tid: 4,_color:'rebeccapurple' },
        { sid: 4, tid: 5 },
        { sid: 5, tid: 6 },
        { sid: 7, tid: 8 },
        { sid: 5, tid: 8 },
        { sid: 3, tid: 8 },
        { sid: 7, tid: 9 }
      ],
      options:
      {
        force: 3000,
        nodeSize: 20,
        nodeLabels: true,
        linkWidth:5
      }
    }
  },
})

```