龙空技术网

D3.js结合vue实现力导向布局

weishuwen 307

前言:

此时各位老铁们对“js动态布局”大约比较讲究,小伙伴们都需要剖析一些“js动态布局”的相关资讯。那么小编同时在网络上汇集了一些关于“js动态布局””的相关知识,希望你们能喜欢,你们一起来了解一下吧!

D3是一个数据可视化的JavaScript函数库,允许用户绑定任意数据到DOM,然后根据数据来操作文档,创建可交互式的图表。Vue是一个响应式的前端框架,能够将数据渲染到DOM并抽象出复杂的逻辑。看起来两个库都能完成数据到DOM的渲染,结合起来可能会出现使用逻辑上的冲突,故尝试D3做数据处理,Vue做数据响应式处理来解决此冲突。

现在完成如下示例:

简单力导布局示例

首先不使用Vue的模板操作,直接使用常规D3.js的Dom操作,包括数据处理、数据显示。

<script>import * as d3 from 'd3'export default {  name: 'demo',  template: '<div></div>',  data () {    return {      width: 600,      height: 400,      nodes: [],      links: []    }  },  mounted () {    const nodes = [      {id: 1, name: '福州'},      {id: 2, name: '宁德'},      {id: 3, name: '莆田'},      {id: 4, name: '泉州'},      {id: 5, name: '厦门'},      {id: 6, name: '漳州'},    ];    const links = [      {source: 1, target: 2},      {source: 1, target: 3},      {source: 1, target: 4},      {source: 3, target: 4},      {source: 4, target: 5},      {source: 4, target: 6},      {source: 5, target: 6},    ];    const svg = d3.select(this.$el)      .append('svg')      .attr('width', this.width)      .attr('height', this.height)    const link = svg.selectAll('line')      .data(links)      .enter()      .append('line')      .attr('stroke', 'red')    const node = svg.selectAll('circle')      .data(nodes)      .enter()      .append('circle')      .attr('fill', 'blue')      .attr('r', '20')    const text = svg.selectAll('text')      .data(nodes)      .enter()      .append('text')      .attr('dx', 0)      .attr('dy', 5)      .attr('fill', 'white')      .attr('text-anchor', 'middle')      .text(d => d.name)        const simulation = d3.forceSimulation(nodes)      .force('charge', d3.forceManyBody().strength(-100))      .force("link", d3.forceLink(links).id(d => d.id).distance(50))      .force("center", d3.forceCenter(this.width / 2, this.height / 2))      .on('tick', () => {        node.attr('cx', d => d.x).attr('cy', d => d.y)        text.attr('x', d => d.x).attr('y', d => d.y)        link.attr('x1', d => d.source.x).attr('y1', d => d.source.y)          .attr('x2', d => d.target.x).attr('y2', d => d.target.y)      })  }}</script>

从代码中可以看出,在不使用模板操作情况下,视图显示操作和逻辑处理其实是混在一起的,现在优化下代码:

<template>  <div class="container" style="cursor: pointer">    <svg ref="svg" :width="width" :height="height">      <g>        <line          v-for="(link, i) in links"          :key="i"          :x1="link.x1"          :x2="link.x2"          :y1="link.y1"          :y2="link.y2"          style="stroke: red"        ></line>      </g>      <g class="node"        style="fill: blue; cursor: pointer;"        :key="node.id"        v-for="node in nodes">        <circle          :cx="node.x"          :cy="node.y"          r="20"        >        </circle>        <text           :x="node.x"          :y="node.y"          dx="0" dy="5"          fill="white"          text-anchor="middle">          {{node.name}}        </text>      </g>    </svg>  </div></template><script>import * as d3 from 'd3'export default {  name: 'demo',  data () {    return {      width: 600,      height: 400,      nodes: [        {id: 1, name: '福州'},        {id: 2, name: '宁德'},        {id: 3, name: '莆田'},        {id: 4, name: '泉州'},        {id: 5, name: '厦门'},        {id: 6, name: '漳州'},      ],      links: [        {source: 1, target: 2},        {source: 1, target: 3},        {source: 1, target: 4},        {source: 3, target: 4},        {source: 4, target: 5},        {source: 4, target: 6},        {source: 5, target: 6},      ],      simulation: ''    }  },  mounted () {    this.simulation = d3.forceSimulation(this.nodes)      .force('charge', d3.forceManyBody().strength(-100))      .force("link", d3.forceLink(this.links).id(d => d.id).distance(50))      .force("center", d3.forceCenter(this.width / 2, this.height / 2))      .on('tick', () => {        this.nodes = this.nodes.map(v => v)        this.links = this.links.map(v => ({          ...v, x1: v.source.x, y1: v.source.y,          x2: v.target.x, y2: v.target.y        }))      })  }}</script>

把对视图操作部分移植到Vue的模板中,很好的利用的Vue的数据响应特性,同时用户交互很容易就能运用到Vue的事件流:

<g class="node"        style="fill: blue; cursor: pointer;"        :key="node.id"        @click="show(node)"        v-for="node in nodes">        ....</g>....methods: {    show(node) {      alert(node.name)    }}....

同时D3内部也提供了方便灵活并且抽象的拖拽交互模块 d3-drag

const node = d3.select(this.$refs.svg).selectAll('.node').data(this.nodes)const drag = d3.drag().on('start', d => {    if (!d3.event.active) {      this.simulation.alphaTarget(0.4).restart();    }    d.fx = d3.event.x;    d.fy = d3.event.y;  }).on('drag', d => {    d.fx = d3.event.x;    d.fy = d3.event.y;  }).on('end', d => {    if (!d3.event.active) {      this.simulation.alphaTarget(0);    }    d.fx = null    d.fy = null  })  node.call(drag)

标签: #js动态布局