D3.js的V5版本-Vue框架中使用(第九章) ---力导向图

一. Api使用

  • d3.forceSimulation() ,新建一个力导向图,
  • d3.forceSimulation().force(),添加或者移除一个力
  • d3.forceSimulation().nodes(),输入是一个数组,然后将这个输入的数组进行一定的数据转换
  • d3.forceLink.links(),这里输入的也是一个数组(边集),然后对输入的边集进行转换
  • tick函数,这个函数对于力导向图来说非常重要,因为力导向图是不断运动的,每一时刻都在发生更新,所以需要不断更新节点和连线的位置
  • d3.drag(),是力导向图可以被拖动   

二. vue使用

<template lang='pug'>
    div.force-pane(:id="id")
        svg
</template>
<script>
/**
 * 力导向图
 */
import * as d3 from 'd3'
let gs = '',
    forceSimulation = '',
    links = '',
    linksText = ''
let nodes = [{ name: '湖南' }, { name: '毛泽东' }, { name: '主席' }]

let edges = [
    { source: 0, target: 1, relation: '籍贯', value: 1.3 },
    { source: 1, target: 2, relation: '职责', value: 1 }
]
export default {
    name: 'Scale',
    data() {
        return {
            id: ''
        }
    },
    methods: {
        uuid() {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1)
            }
            return (
                s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4()
            )
        },
        ticked() {
            links
                .attr('x1', function(d) {
                    return d.source.x
                })
                .attr('y1', function(d) {
                    return d.source.y
                })
                .attr('x2', function(d) {
                    return d.target.x
                })
                .attr('y2', function(d) {
                    return d.target.y
                })

            linksText
                .attr('x', function(d) {
                    return (d.source.x + d.target.x) / 2
                })
                .attr('y', function(d) {
                    return (d.source.y + d.target.y) / 2
                })

            gs.attr('transform', d => {
                return 'translate(' + d.x + ',' + d.y + ')'
            })
        },
        dragStart(d) {
            if (!d3.event.active) {
                //设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1]
                forceSimulation.alphaTarget(0.8).restart()
            }
            d.fx = d.x
            d.fy = d.y
        },
        dragEnd(d) {
            d.fx = d3.event.x
            d.fy = d3.event.y
        },
        drag(d) {
            if (!d3.event.active) {
                forceSimulation.alphaTarget(0)
            }
            d.fx = null
            d.fy = null
        }
    },
    created() {
        this.id = this.uuid()
    },
    mounted() {
        //1.创建svg画布
        let marge = { top: 160, bottom: 60, left: 160, right: 60 }
        let width = document.getElementById(this.id).clientWidth
        let height = document.getElementById(this.id).clientHeight
        const svg = d3
            .select(this.$el)
            .select('svg')
            .attr('width', width)
            .attr('height', height)
        let g = svg
            .append('g')
            .attr(
                'transform',
                'translate(' + marge.top + ',' + marge.left + ')'
            )

        //2.设置一个color的颜色比例尺,为了让不同的扇形呈现不同的颜色
        var colorScale = d3
            .scaleOrdinal()
            .domain(d3.range(nodes.length))
            .range(d3.schemeCategory10)

        //3.新建一个力导向图
        forceSimulation = d3
            .forceSimulation()
            .force('link', d3.forceLink())
            .force('charge', d3.forceManyBody())
            .force('center', d3.forceCenter())

        //4. 初始化力导向图
        //生成节点数据
        forceSimulation.nodes(nodes).on('tick', this.ticked)
        //生成边数据
        forceSimulation
            .force('link')
            .links(edges)
            .distance(function(d) {
                //每一边的长度
                return d.value * 100
            })
        //设置图形的中心位置
        forceSimulation
            .force('center')
            .x(width / 4)
            .y(height / 4)

        //5. 绘制边(有了节点和边的数据后)
        links = g
            .append('g')
            .selectAll('line')
            .data(edges)
            .enter()
            .append('line')
            .attr('stroke', function(d, i) {
                return colorScale(i)
            })
            .attr('stroke-width', 1)
        linksText = g
            .append('g')
            .selectAll('text')
            .data(edges)
            .enter()
            .append('text')
            .text(function(d) {
                return d.relation
            })

        //6. 绘制节点, 先为节点和节点上的文字分组
        gs = g
            .selectAll('.circleText')
            .data(nodes)
            .enter()
            .append('g')
            .attr('transform', function(d, i) {
                var cirX = d.x
                var cirY = d.y
                return 'translate(' + cirX + ',' + cirY + ')'
            })
            .call(
                d3
                    .drag()
                    .on('start', this.dragStart)
                    .on('drag', this.drag)
                    .on('end', this.dragEnd)
            )

        //绘制节点
        gs.append('circle')
            .attr('r', 10)
            .attr('fill', function(d, i) {
                return colorScale(i)
            })
        //文字
        gs.append('text')
            .attr('x', -10)
            .attr('y', -20)
            .attr('dy', 10)
            .text(function(d) {
                return d.name
            })
    }
}
</script>
<style lang='scss' scoped>
.force-pane {
    width: 100%;
    height: 1000px;
}
</style>

猜你喜欢

转载自blog.csdn.net/davidpan1234/article/details/81069996