如何为Vue.js实现D3 [英] How to implement D3 for Vue.js

查看:123
本文介绍了如何为Vue.js实现D3的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用React可以实现D3的各种实现.其中一个更有趣的项目是使用 react-faux-dom 项目.这种方法的优势在于,React可以了解D3创建的DOM元素以及创建同构图的能力.

There are various implementations of D3 with React. One of the more interesting ones uses the react-faux-dom project. Advantages to this approach are that React knows about DOM elements created by D3 and the ability to create isomorphic charts.

请参阅以下内容:

  • http://oli.me.uk/2015/09/09/d3-within-react-the-right-way/
  • https://github.com/Olical/react-faux-dom
  • http://www.reactd3.org/

在具有相同优势的Vue.js中实现D3会怎样?

What would it take to implement D3 in Vue.js with the same benefits?

是否需要创建类似于react-faux-dom的内容,或者Vue是否已经有可用于此目的的内容?

Is there a need to create something similar to react-faux-dom or does Vue already have something that can be used for this?

考虑Vue的体系结构,这种方法有什么意义(或没有意义)?

How does this approach make sense (or not) considering Vue’s architecture?

推荐答案

从版本4开始,D3已高度模块化,计算部分在较小的库中得到了很好的隔离,例如

Since version 4, D3 is highly modularized and computational parts are well isolated in small librairies, such as d3-force. One approach I like is to let Vue.js handle DOM manipulation and events, and use d3.js for computations. Your visualization component is similar to your other components, and are easier to understand for someone familiar with Vue.js but not d3.js.

我创建了 codepen 来显示力图实现:

I created a codepen to show a force graph implementation :

HTML:

<div id="app">
  <svg xmlns="http://www.w3.org/2000/svg" :width="width+'px'" :height="height+'px'" @mousemove="drag($event)" @mouseup="drop()" v-if="bounds.minX">
    <line v-for="link in graph.links" :x1="coords[link.source.index].x" :y1="coords[link.source.index].y" :x2="coords[link.target.index].x" :y2="coords[link.target.index].y" stroke="black" stroke-width="2"/>
    <circle v-for="(node, i) in graph.nodes" :cx="coords[i].x" :cy="coords[i].y" :r="20" :fill="colors[Math.ceil(Math.sqrt(node.index))]" stroke="white" stroke-width="1" @mousedown="currentMove = {x: $event.screenX, y: $event.screenY, node: node}"/>
  </svg>
</div>

Javascript:

Javascript:

new Vue({
  el: '#app',
  data: {
    graph: {
      nodes: d3.range(100).map(i => ({ index: i, x: null, y: null })),
      links: d3.range(99).map(i => ({ source: Math.floor(Math.sqrt(i)), target: i + 1 }))
    },
    width: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
    height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - 40,
    padding: 20,
    colors: ['#2196F3', '#E91E63', '#7E57C2', '#009688', '#00BCD4', '#EF6C00', '#4CAF50', '#FF9800', '#F44336', '#CDDC39', '#9C27B0'],
    simulation: null,
    currentMove: null
  },
  computed: {
    bounds() {
      return {
        minX: Math.min(...this.graph.nodes.map(n => n.x)),
        maxX: Math.max(...this.graph.nodes.map(n => n.x)),
        minY: Math.min(...this.graph.nodes.map(n => n.y)),
        maxY: Math.max(...this.graph.nodes.map(n => n.y))
      }
    },
    coords() {
      return this.graph.nodes.map(node => {
        return {
          x: this.padding + (node.x - this.bounds.minX) * (this.width - 2*this.padding) / (this.bounds.maxX - this.bounds.minX),
          y: this.padding + (node.y - this.bounds.minY) * (this.height - 2*this.padding) / (this.bounds.maxY - this.bounds.minY)
        }
      })
    }
  },
  created(){
     this.simulation = d3.forceSimulation(this.graph.nodes)
        .force('charge', d3.forceManyBody().strength(d => -100))
        .force('link', d3.forceLink(this.graph.links))
        .force('x', d3.forceX())
        .force('y', d3.forceY())
  },
  methods: {
    drag(e) {
      if (this.currentMove) {
        this.currentMove.node.fx = this.currentMove.node.x - (this.currentMove.x - e.screenX) * (this.bounds.maxX - this.bounds.minX) / (this.width - 2 * this.padding)
        this.currentMove.node.fy = this.currentMove.node.y -(this.currentMove.y - e.screenY) * (this.bounds.maxY - this.bounds.minY) / (this.height - 2 * this.padding)
        this.currentMove.x = e.screenX
        this.currentMove.y = e.screenY
      }
    },
    drop(){
      delete this.currentMove.node.fx
      delete this.currentMove.node.fy    
      this.currentMove = null
      this.simulation.alpha(1)
      this.simulation.restart()
    }
  }
})

我看到的主要缺点是,如果您要在Vue.js应用程序中重用较大的d3.js代码库,则必须重写它.您还会发现很多用纯d3.js语法编写的示例,您将不得不对其进行调整.

The main drawback I see is if you have a large d3.js codebase you want to reuse in your Vue.js application as you will have to rewrite it. You will also find a lot of examples written in pure d3.js syntax and you will have to adapt them.

这篇关于如何为Vue.js实现D3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆