D3.js结合canvas在vue框架下画力导向图出错,只画出了圆,却没有体现力

attenton
  • 2
新手上路,请多包涵

我在使用d3.js画力导向图时,出现了画出了圆,但是不是力导向图,并且圆也只是在角落里。无论我怎么改变forceCenter的参数,都没有用,感觉只是canvas生效而d3的force没有生效。
实现后的截图:

clipboard.png

具体代码如下:

<template>
  <div id='force_graph'>
    <h1>hello</h1>
    <div id='graph_canvas'>
      <canvas ref="canvas" height=600 width=1300></canvas>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3'

export default {
  name: 'forceGraph',
  data () {
    return {
      nodes: [
        {id: 1, name: 'javascript', color: 'pink'},
        {id: 2, name: 'java', color: 'green'},
        {id: 3, name: 'c++', color: 'blue'},
        {id: 4, name: 'python', color: 'grey'},
        {id: 5, name: 'php', color: 'red'}
      ],
      edges: [
        {source: 1, target: 3},
        {source: 2, target: 4},
        {source: 3, target: 5},
        {source: 4, target: 5}
      ],
      graph: null,
      width: 1300,
      height: 600,
      strength: -20,
      link_distance: 30,
      canvas: document.querySelector('canvas'),
      e: null
    }
  },
  methods: {
    render (e) {
      e.clearRect(0, 0, this.height, this.width)
      e.lineWidth = 2
      e.strokeStyle = 'white'
      e.beginPath()
      this.edges.forEach(function (a) {
        e.moveTo(a.source.x, a.source.y)
        e.lineTo(a.target.x, a.target.y)
      })
      e.stroke()
      e.lineWidth = 3
      e.strokeStyle = 'black'
      this.nodes.forEach(function (a) {
        e.fillStyle = a.color
        e.beginPath()
        e.arc(a.x, a.y, 200, 0, 2 * Math.PI)
        e.fill()
        e.stroke()
      })
      e.font = '14px Comic Sans MS'
      e.fillStyle = 'black'
      e.textAlign = 'center'
      this.nodes.forEach(function (a) {
        e.fillText(a.name, a.x, a.y + 2.5 * 12)
      })
    },
    force_graph_init () {
      const canvas = document.querySelector('canvas')
      console.log(canvas)
      console.log('ah:nodes')
      console.log(this.nodes)
      this.nodes.push({id: 6, name: 'c', color: 'brown'})
      this.e = canvas.getContext('2d')
      this.width = canvas.width
      this.height = canvas.height
      this.graph = d3.forceSimulation().force('center', d3.forceCenter(-1000, -1000))
      console.log('graph')
      console.log(this.graph)
      this.graph.force('charge', d3.forceManyBody())
        .force('collide', d3.forceCollide(1.2 * 12))
        .force('link', d3.forceLink().id(function (d) { return d.id }).distance(this.link_distance))
      console.log('be:nodes')
      console.log(this.nodes)
      this.graph.nodes(this.nodes).on('tick', this.render(this.e))
      // this.graph.force('link', d3.forceLink().id(function (a) { return a.id }).distance(this.link_distance))
      this.graph.force('link').links(this.edges)
      // d3.select(canvas).call(d3.drag().container(canvas).subject(function () { return this.graph.find(d3.event.x, d3.event.y) })
      //   .on('start', function () {
      //     d3.event.active || this.graph.alphTarget(0.3).restart()
      //     d3.event.subject.fx = d3.event.subject.x
      //     d3.event.subject.fy = d3.event.subject.y
      //   }).on('drag', function () {
      //     d3.event.subject.fx = d3.event.x
      //     d3.event.subject.fy = d3.event.y
      //   }).on('end', function () {
      //     d3.event.active || this.graph.alphaTarget(0)
      //     d3.event.subject.fx = null
      //     d3.event.subject.fy = null
      //   }))
      this.restart()
      console.log(this.graph)
      console.log('nodes:')
      console.log(this.nodes)
      console.log('edges')
      console.log(this.edges)
      // this.pause()
    },
    initDrag () {

    },
    run () {
      this.graph.restart()
    },
    restart () {
      this.graph.alpha(1)
      this.run()
    },
    pause () {
      this.graph.stop()
    }
  },
  mounted () {
    this.force_graph_init()
  }
}
</script>

<style scoped>
#graph_canvas{
  width: 900px;
  margin: 20px auto;
}
</style>

ps:注释部分是可拖拽部分,所以就先注释了。

回复
阅读 2.4k
1 个回答
<template>
  <div id='force_graph'>
    <h1>hello</h1>
    <div id='graph_canvas'>
      <canvas ref="canvas" height=600 width=1300></canvas>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3'

export default {
  name: 'forceGraph',
  data () {
    return {
      nodes: [
        {id: 1, name: 'javascript', color: 'pink'},
        {id: 2, name: 'java', color: 'green'},
        {id: 3, name: 'c++', color: 'blue'},
        {id: 4, name: 'python', color: 'grey'},
        {id: 5, name: 'php', color: 'red'}
      ],
      edges: [
        {source: 1, target: 3},
        {source: 2, target: 4},
        {source: 3, target: 5},
        {source: 4, target: 5}
      ],
      graph: null,
      width: 1300,
      height: 600,
      strength: -20,
      link_distance:100,
      canvas: document.querySelector('canvas'),
      e: null
    }
  },
  methods: {
    render () {
        let e = this.e;
      e.clearRect(0, 0, this.width, this.height)
      this.edges.forEach(function (a) {
           e.beginPath()
        e.moveTo(a.source.x, a.source.y)
        e.lineTo(a.target.x, a.target.y)
         e.stroke()
      })
    
      this.nodes.forEach(function (a) {
        e.fillStyle = a.color
        e.beginPath()
        e.arc(a.x, a.y, 20, 0, 2 * Math.PI)
        e.fill()
        e.stroke()
      })
      e.font = '14px Comic Sans MS'
      e.fillStyle = 'black'
      e.textAlign = 'center'
      this.nodes.forEach(function (a) {
        e.fillText(a.name, a.x, a.y + 2.5 * 12)
      });
    },
    force_graph_init () {
      const canvas = document.querySelector('canvas')
      console.log(canvas)
      console.log('ah:nodes')
      console.log(this.nodes)
      this.nodes.push({id: 6, name: 'c', color: 'brown'})
      this.e = canvas.getContext('2d')
      this.width = canvas.width
      this.height = canvas.height
      this.graph = d3.forceSimulation().force('center', d3.forceCenter(this.width/2, this.height/2))
      console.log('graph')
      console.log(this.graph)
      this.graph.force('charge', d3.forceManyBody())
        .force('collide', d3.forceCollide(1.2 * 12))
        .force('link', d3.forceLink().id(function (d) { return d.id }).distance(this.link_distance))
      console.log('be:nodes')
      console.log(this.nodes)
      this.graph.nodes(this.nodes).on('tick', this.render)
      // this.graph.force('link', d3.forceLink().id(function (a) { return a.id }).distance(this.link_distance))
      this.graph.force('link').links(this.edges)
      // d3.select(canvas).call(d3.drag().container(canvas).subject(function () { return this.graph.find(d3.event.x, d3.event.y) })
      //   .on('start', function () {
      //     d3.event.active || this.graph.alphTarget(0.3).restart()
      //     d3.event.subject.fx = d3.event.subject.x
      //     d3.event.subject.fy = d3.event.subject.y
      //   }).on('drag', function () {
      //     d3.event.subject.fx = d3.event.x
      //     d3.event.subject.fy = d3.event.y
      //   }).on('end', function () {
      //     d3.event.active || this.graph.alphaTarget(0)
      //     d3.event.subject.fx = null
      //     d3.event.subject.fy = null
      //   }))
    //   this.restart()
      console.log(this.graph)
      console.log('nodes:')
      console.log(this.nodes)
      console.log('edges')
      console.log(this.edges)
      // this.pause()
    },
    initDrag () {

    },
    run () {
      this.graph.restart()
    },
    restart () {
      this.graph.alpha(1)
      this.run()
    },
    pause () {
      this.graph.stop()
    }
  },
  mounted () {
    this.force_graph_init()
  }
}
</script>

<style scoped>
#graph_canvas{
  width: 900px;
  margin: 20px auto;
}
</style>

主要是你的render加了括号,这就不是传入函数而是将它执行且执行一次而已,所以节点都画在了圆点,另外一些参数有点错误或者需要优化。

宣传栏