d3-V5 力引導佈局實例圖

環境vue組件中 

<template>
  <div>
    <svg width="960" height="600"></svg>
  </div>
</template>
<script>
/* eslint-disable  no-param-reassign */
import * as d3 from 'd3';
// 準備數據
const nodes = [
  { id: '湖南邵陽', group: '頭暈' },
  { id: '山東萊州', group: '頭暈' },
  { id: '廣東陽江', group: '體徵' },
  { id: '山東棗莊', group: '部位' },
  { id: '澤', group: '頭暈' },
  { id: '恆', group: '體徵' },
  { id: '鑫', group: '部位' },
  { id: '明山', group: '頭暈' },
  { id: '班長', group: '體徵' },
];
const leng = [
  { group: '頭暈' },
  { group: '部位' },
  { group: '體徵' },

];
const edges = [
  { source: '湖南邵陽', target: '山東萊州' },
  { source: '山東萊州', target: '廣東陽江' },
  { source: '山東棗莊', target: '澤' },
  { source: '明山', target: '澤' },
  { source: '班長', target: '明山' },
  { source: '明山', target: '澤' },
  { source: '恆', target: '鑫' },
  { source: '廣東陽江', target: '班長' },
  { source: '恆', target: '澤' },
  { source: '明山', target: '班長' },
];
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);

// 新建一個力導向圖
const forceSimulation = d3.forceSimulation()
  .force('link', d3.forceLink().id(d => d.id))
  .force('charge', d3.forceManyBody())
  .force('center', d3.forceCenter());
export default {
  data() {
    return {
      links: '',
      linksText: '',
      gs: '',
    };
  },
  mounted() {
    const marge = { top: 60, bottom: 60, left: 60, right: 60 };
    const svg = d3.select('svg');
    const width = svg.attr('width');
    const height = svg.attr('height');
    const g = svg.append('g')
      .attr('transform', `translate(${marge.top},${marge.left})`);
    svg.call(
      d3.zoom()
        .scaleExtent([0.1, 4])
        .on('zoom', () => { g.attr('transform', d3.event.transform); }),
    );
    svg.selectAll('rect')
      .data(leng)
      .enter()
      .append('rect')
      .attr('x', (d, i) => i * 70)
      .attr('y', 20)
      .attr('class', 'legend')
      .attr('width', 25)
      .attr('height', 15)
      .attr('rx', 4)
      .attr('ry', 4)
      .style('fill', d => colorScale(d.group));

    svg.selectAll('.text')
      .data(leng)
      .enter()
      .append('text')
      .attr('class', 'Text')
      .attr('x', (d, i) => 25 + i * 70)
      .attr('y', 32)
      .attr('transform', 'translate(5)')
      .text(d => d.group);


    forceSimulation.nodes(nodes)
      .on('tick', this.ticked);// 這個函數很重要,後面給出具體實現和說明
    // 生成邊數據
    forceSimulation.force('link')
      .links(edges)
      .distance(() => 200);
    // 設置圖形的中心位置
    forceSimulation.force('center')
      .x(width / 2)
      .y(height / 2);
    // 在瀏覽器的控制檯輸出
    console.log(nodes);
    console.log(edges);

    // 有了節點和邊的數據後,我們開始繪製
    // 繪製邊
    this.links = g.append('g')
      .selectAll('line')
      .data(edges)
      .enter()
      .append('line')
      .attr('stroke', '#ccc')
      .attr('stroke-width', 1);
    // 繪製節點
    // 老規矩,先爲節點和節點上的文字分組
    this.gs = g.selectAll('.circleText')
      .data(nodes)
      .enter()
      .append('g')
      .attr('transform', (d) => {
        const cirX = d.x;
        const cirY = d.y;
        return `translate(${cirX},${cirY})`;
      })
      .call(d3.drag()
        .on('start', this.started)
        .on('drag', this.dragged)
        .on('end', this.ended));

    // 繪製節點
    this.gs.append('circle')
      .attr('class', 'hover')
      .attr('r', 15)
      .attr('fill', d => colorScale(d.group))
      .on('mouseover', function () {
        d3.select(this)
          .attr('r', 17)
          .attr('stroke', '#D3D3D3')
          .attr('stroke-width', 1);
      })
      .on('mouseout', function () {
        d3.select(this)
          .transition()
          .duration(300)
          .attr('fill', d => colorScale(d.group))
          .attr('r', 15)
          .attr('stroke', 'none');
      });


    // 文字
    this.gs.append('text')
      .attr('x', -15)
      .attr('y', -28)
      .attr('dy', 10)
      .attr('fill', d => colorScale(d.group))
      .text(d => d.id);
  },
  methods: {
    ticked() {
      this.links
        .attr('x1', d => d.source.x)
        .attr('y1', d => d.source.y)
        .attr('x2', d => d.target.x)
        .attr('y2', d => d.target.y);
      this.gs
        .attr('transform', d => `translate(${d.x},${d.y})`);
    },
    started(d) {
      if (!d3.event.active) {
        forceSimulation.alphaTarget(0.8).restart();
      }
      d.fx = d.x;
      d.fy = d.y;
    },
    dragged(d) {
      d.fx = d3.event.x;
      d.fy = d3.event.y;
    },
    ended(d) {
      if (!d3.event.active) {
        forceSimulation.alphaTarget(0);
      }
      d.fx = null;
      d.fy = null;
    },
  },
};
</script>
<style scoped>
  .title { background: red;}
  .text{ font-size: 12px;}
  .hover:hover{ border: 5px solid #ccc;}
  .legend {
    position: fixed;
    font: 10px sans-serif;
    box-shadow: 2px 2px 1px #888;
  }
</style>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章