d3.js - 如何为 Vue.js 实现 D3

标签 d3.js vue.js

D3 与 React 有多种实现。其中一个比较有趣的是使用 react-faux-dom 项目。这种方法的优点是 React 了解 D3 创建的 DOM 元素以及创建同构图表的能力。

引用以下内容:

在 Vue.js 中实现 D3 并获得相同的好处需要什么?

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

考虑到 Vue 的架构,这种方法有何意义(或没有意义)?

最佳答案

从版本 4 开始,D3 高度模块化,计算部分在小型库中得到很好的隔离,例如 d3-force .我喜欢的一种方法是让 Vue.js 处理 DOM 操作和事件,并使用 d3.js 进行计算。您的可视化组件与您的其他组件类似,对于熟悉 Vue.js 但不熟悉 d3.js 的人来说更容易理解。

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

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:

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()
    }
  }
})

我看到的主要缺点是,如果你有一个大型 d3.js 代码库,你想在你的 Vue.js 应用程序中重用,因为你将不得不重写它。您还会发现很多用纯 d3.js 语法编写的示例,您将不得不调整它们。

关于d3.js - 如何为 Vue.js 实现 D3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41067022/

相关文章:

javascript - D3 隐藏图表区域的溢出,当Y轴有最小值和最大值时

javascript - 向 d3.js 折线图添加图例

javascript - D3 图表上的顶部标签被切断

javascript - Vue.js - 插值错误 - 如何将样式重新设计为 v-bind :style?

javascript - axios.all的动态使用

vue.js - vuejs 设置一个单选按钮检查语句是否为真

vue.js - Nuxt 2.15.7 构建错误 - 无法解析 CSS @font-face URL

svg - 以编程方式将 D3.js 图形导出到静态 SVG 文件

javascript - D3 退出转换 : animation translate to left before remove

javascript - 我可以让 Vue.js 跨站点保持事件状态吗?