精华内容
下载资源
问答
  • 2017年5月8日一、背景力导向图非常适合于渲染关系型信息图。二、什么是力导向图(Force-directed)?我们可以把整张 Network 想象成一个物理仿真系统(Simulation)。系统中的每个节点(Node)都是一个带有能量的粒子,...

    2017年5月8日

    一、背景

    力导向图非常适合于渲染关系型信息图。

    二、什么是力导向图(Force-directed)?

    我们可以把整张 Network 想象成一个物理仿真系统(Simulation)。系统中的每个节点(Node)都是一个带有能量的粒子,粒子与粒子之间存在斥力(如模拟库伦斥力),而被边(Link)所连结的粒子受到牵引力(如模拟胡克弹力)。系统中的粒子在斥力和引力的不断作用下,从随机无序的布局(Layout)不断发生位移,逐渐趋于平衡有序的布局。同时整个仿真系统的能量也在不断消耗,经过数次迭代后,粒子之间不再发生相对位移,整个系统达到最终稳定平衡的状态。

    d11f0d2719ad

    此动效实现的本质就是每一帧都重新渲染图中节点的位置(x,y), 节点的位置(x,y)是由节点上一帧所处的位置(x,y)+速度(vx,vy)所决定的。而速度就是通过力学模型所计算出来的。

    关键在于力(Forces),D3.js 中内置了几种经典的力模型:

    1. 中心力(Centering)

    中心力可以使得节点最终布局是围绕着某个中心的。相当于某个中心点对所有的节点都有一个制约,不会让布局的中心偏离。

    2. 碰撞力(Collision)

    d11f0d2719ad

    碰撞力为每个节点都设定一个圆形的碰撞区域,从而防止节点之间重叠。

    关键参数:radius 碰撞半径

    3. 牵引力(Links)

    d11f0d2719ad

    牵引力的强度与节点之间的距离成正比,类似于弹簧力。

    关键参数:distance。影响两个节点之间的最终距离。

    4. N 体力(Many-Body)

    N体问题是天体力学的一种力学模型,它研究 N 个质点相互之间在万有引力作用下的运动规律。

    Many-Body 力是作用于所有节点之间的,是全局的,任何两个节点之间都将受到此力的影响。(与 牵引力 Links 不同,Links 力仅仅会影响有连接关系的两个节点)

    它可以用来模拟引力(吸引力),只需设置的 strength 参数为正数;

    它也可用来模拟电荷力(排斥力),只需设置的 strength 参数为负数。

    实现算法使用了 the Barnes–Hut approximation(通过将平面不断递归地划分成四个小区域来构建一棵四叉树) 来提高性能;

    5. 方向力(Positioning)

    方向力分为 X 方向和 Y 方向,即将作用力限制在一个维度上( X 维度或者 Y 维度)

    说明

    以上这几个力学模型是 D3.js 封装的几个经典力学模型,开发者也可根据自身的业务场景,应用自定义的力模型;

    力模型是可以多重复叠加的,即可同时叠加中心力、碰撞力、牵引力等等;

    三、最终效果

    d11f0d2719ad

    通过控制右侧面板,所见即所得地为 Chart 添加不同的力,用户可灵活定制想要的效果。

    d11f0d2719ad

    四、相关资料

    展开全文
  • 力导向图.links line{stroke:#999;stroke-opacity:0.6;}.nodes circle{stroke:#fff;stroke-width:1.5px;}varnodes=[{ name:"虚拟助理APP",group:1},{ name:"桥梁结构",group:1},{ name:"钢桁梁",group:1},{ name:...

    varnodes=[

    { name:"虚拟助理APP",group:1},

    { name:"桥梁结构",group:1},

    { name:"钢桁梁",group:1},

    { name:"上弦杆",group:1},

    { name:"下弦杆",group:1},

    { name:"桥面系",group:1},

    { name:"支座",group:1},

    { name:"声屏障",group:1},

    { name:"螺栓",group:1},

    { name:"螺栓病害",group:1},

    { name:"折断",group:1},

    { name:"缺失",group:1},

    { name:"其他",group:1},

    { name:"螺栓养护",group:1},

    { name:"涂装",group:1},

    { name:"补拧",group:1},

    { name:"除锈",group:1},

    { name:"螺栓维修",group:1},

    { name:"更换",group:1},

    { name:"补拧",group:1},

    { name:"斜拉桥",group:1},

    { name:"悬索桥",group:1},

    { name:"系杆拱",group:1}

    ];varedges=[

    { source :0, target:1} ,

    { source :1, target:2} ,

    { source :2, target:3},

    { source :2, target:4},

    { source :2, target:5},

    { source :2, target:6},

    { source :2, target:7},

    { source :2, target:8},

    { source :8, target:9},

    { source :9, target:10},

    { source :9, target:11},

    { source :9, target:12},

    { source :8, target:13},

    { source :13, target:14},

    { source :13, target:15},

    { source :13, target:16},

    { source :8, target:17},

    { source :17, target:18},

    { source :17, target:19},

    { source :1, target:20} ,

    { source :1, target:21} ,

    { source :1, target:22}

    ];varwidth= 1000;varheight=1000;varsvg=d3.select("body")

    .append("svg")

    .attr("width",width)

    .attr("height",height);varforce=d3.layout.force()

    .nodes(nodes)//指定节点数组

    .links(edges)//指定连线数组

    .size([width,height])//指定范围

    .linkDistance(150)//指定连线长度

    .charge(-400);//相互之间的作用力

    force.start();//开始作用

    console.log(nodes);

    console.log(edges);//添加连线

    varsvg_edges=svg.selectAll("line")

    .data(edges)

    .attr("class","links")

    .enter()

    .append("line")

    .style("stroke","#ccc")

    .style("stroke-width",1);varcolor=d3.scale.category20();//添加节点

    varsvg_nodes=svg.selectAll("circle")

    .data(nodes)

    .attr("class","nodes")

    .enter()

    .append("circle")

    .attr("r",20)

    .style("fill",function(d,i){returncolor(i);

    })

    .call(force.drag);//使得节点能够拖动

    //添加描述节点的文字

    varsvg_texts=svg.selectAll("text")

    .data(nodes)

    .enter()

    .append("text")

    .style("fill","black")

    .attr("dx",20)

    .attr("dy",8)

    .text(function(d){returnd.name;

    });

    force.on("tick",function(){//对于每一个时间间隔

    //更新连线坐标

    svg_edges.attr("x1",function(d){returnd.source.x; })

    .attr("y1",function(d){returnd.source.y; })

    .attr("x2",function(d){returnd.target.x; })

    .attr("y2",function(d){returnd.target.y; });//更新节点坐标

    svg_nodes.attr("cx",function(d){returnd.x; })

    .attr("cy",function(d){returnd.y; });//更新文字坐标

    svg_texts.attr("x",function(d){returnd.x; })

    .attr("y",function(d){returnd.y; });

    });

    展开全文
  • D3js力导向图搭建d3js是一个可以基于数据来操作文档的JavaScript库。可以使用HTML,CSS,SVG以及Canvas来展示数据。力导向图能够用来表示节点间多对多的关系。实现效果:连线有箭头,点击节点能改变该节点颜色和所连接...

    D3js力导向图搭建

    d3js是一个可以基于数据来操作文档的JavaScript库。可以使用HTML,CSS,SVG以及Canvas来展示数据。力导向图能够用来表示节点间多对多的关系。

    实现效果:连线有箭头,点击节点能改变该节点颜色和所连接的线的粗细,缩放、拖拽。

    版本:4.X

    e258349db14fa86095c614cd005b6ee5.png

    安装和导入

    npm安装:npm install d3

    前端导入:import * as d3 from 'd3';

    一、完整代码

    import React, { Component } from 'react';

    import PropTypes from 'prop-types';

    import { connect } from 'react-redux';

    import { push } from 'react-router-redux';

    import * as d3 from 'd3';

    import { Row, Form } from 'antd';

    import { chartReq} from './actionCreator';

    import './Chart.less';

    const WIDTH = 1900;

    const HEIGHT = 580;

    const R = 30;

    let simulation;

    class Chart extends Component {

    constructor(props, context) {

    super(props, context);

    this.print = this.print.bind(this);

    this.forceChart = this.forceChart.bind(this);

    this.state = {

    };

    }

    componentWillMount() {

    this.props.dispatch(push('/Chart'));

    }

    componentDidMount() {

    this.print();

    }

    print() {

    let callback = (res) => { // callback获取后台返回的数据,并存入state

    let nodeData = res.data.nodes;

    let relationData = res.data.rels;

    this.setState({

    nodeData: res.data.nodes,

    relationData: res.data.rels,

    });

    let nodes = [];

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '',

    type: (nodeData[i] && nodeData[i].type) || '',

    definition: (nodeData[i] && nodeData[i].definition) || '',

    });

    }

    let edges = [];

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '',

    target: (relationData[i] && relationData[i].end.id) || '',

    tag: (relationData[i] && relationData[i].name) || '',

    });

    }

    this.forceChart(nodes, edges); // d3力导向图内容

    };

    this.props.dispatch(chartReq({ param: param }, callback));

    }

    // func

    forceChart(nodes, edges) {

    this.refs['theChart'].innerHTML = '';

    // 函数内其余代码请看拆解代码

    }

    render() {

    return (

    );

    }

    }

    Chart.propTypes = {

    dispatch: PropTypes.func.isRequired,

    };

    function mapStateToProps(state) {

    return {

    };

    }

    const WrappedChart = Form.create({})(Chart);

    export default connect(mapStateToProps)(WrappedChart);

    二、拆解代码

    1.组件

    整个图都将在div里绘制。

    2.构造节点和连线

    let nodes = []; // 节点

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '', // 节点名称

    });

    }

    let edges = []; // 连线

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '', // 开始节点

    target: (relationData[i] && relationData[i].end.id) || '', // 结束节点

    tag: (relationData[i] && relationData[i].name) || '', // 连线名称

    });

    }

    具体怎么构造依据你们的项目数据。

    3.定义力模型

    const simulation = d3.forceSimulation(nodes) // 指定被引用的nodes数组

    .force('link', d3.forceLink(edges).id(d => d.id).distance(150))

    .force('collision', d3.forceCollide(1).strength(0.1))

    .force('center', d3.forceCenter(WIDTH / 2, HEIGHT / 2))

    .force('charge', d3.forceManyBody().strength(-1000).distanceMax(800));

    通过simulation.force()设置力,可以设置这几种力:

    Centering:中心力,设置图中心点位置。

    Collision:节点碰撞作用力,.strength参数范围为[0,1]。

    Links:连线的作用力;.distance设置连线两端节点的距离。

    Many-Body:.strength的参数为正时,模拟重力,为负时,模拟电荷力;.distanceMax的参数设置最大距离。

    Positioning:给定向某个方向的力。

    通过simulation.on监听力图元素位置变化。

    4.绘制svg

    const svg = d3.select('#theChart').append('svg') // 在id为‘theChart'的标签内创建svg

    .style('width', WIDTH)

    .style('height', HEIGHT * 0.9)

    .on('click', () => {

    console.log('click', d3.event.target.tagName);

    })

    .call(zoom); // 缩放

    const g = svg.append('g'); // 则svg中创建g

    创建svg,在svg里创建g,将节点连线等内容放在g内。

    select:选择第一个对应的元素

    selectAll:选择所有对应的元素

    append:创建元素

    5.绘制连线

    const edgesLine = svg.select('g')

    .selectAll('line')

    .data(edges) // 绑定数据

    .enter() // 添加数据到选择集edgepath

    .append('path') // 生成折线

    .attr('d', (d) => { return d && 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y; }) // 遍历所有数据,d表示当前遍历到的数据,返回绘制的贝塞尔曲线

    .attr('id', (d, i) => { return i && 'edgepath' + i; }) // 设置id,用于连线文字

    .attr('marker-end', 'url(#arrow)') // 根据箭头标记的id号标记箭头

    .style('stroke', '#000') // 颜色

    .style('stroke-width', 1); // 粗细

    连线用贝塞尔曲线绘制:(M  起点X  起点y  L  终点x  终点y)

    6.绘制连线上的箭头

    const defs = g.append('defs'); // defs定义可重复使用的元素

    const arrowheads = defs.append('marker') // 创建箭头

    .attr('id', 'arrow')

    // .attr('markerUnits', 'strokeWidth') // 设置为strokeWidth箭头会随着线的粗细进行缩放

    .attr('markerUnits', 'userSpaceOnUse') // 设置为userSpaceOnUse箭头不受连接元素的影响

    .attr('class', 'arrowhead')

    .attr('markerWidth', 20) // viewport

    .attr('markerHeight', 20) // viewport

    .attr('viewBox', '0 0 20 20') // viewBox

    .attr('refX', 9.3 + R) // 偏离圆心距离

    .attr('refY', 5) // 偏离圆心距离

    .attr('orient', 'auto'); // 绘制方向,可设定为:auto(自动确认方向)和 角度值

    arrowheads.append('path')

    .attr('d', 'M0,0 L0,10 L10,5 z') // d: 路径描述,贝塞尔曲线

    .attr('fill', '#000'); // 填充颜色

    viewport:可视区域

    viewBox:实际大小,会自动缩放填充viewport

    7.绘制节点

    const nodesCircle = svg.select('g')

    .selectAll('circle')

    .data(nodes)

    .enter()

    .append('circle') // 创建圆

    .attr('r', 30) // 半径

    .style('fill', '#9FF') // 填充颜色

    .style('stroke', '#0CF') // 边框颜色

    .style('stroke-width', 2) // 边框粗细

    .on('click', (node) => { // 点击事件

    console.log('click');

    })

    .call(drag); // 拖拽单个节点带动整个图

    创建圆作为节点。

    .call()调用拖拽函数。

    8.节点名称

    const nodesTexts = svg.select('g')

    .selectAll('text')

    .data(nodes)

    .enter()

    .append('text')

    .attr('dy', '.3em') // 偏移量

    .attr('text-anchor', 'middle') // 节点名称放在圆圈中间位置

    .style('fill', 'black') // 颜色

    .style('pointer-events', 'none') // 禁止鼠标事件

    .text((d) => { // 文字内容

    return d && d.name; // 遍历nodes每一项,获取对应的name

    });

    因为文字在节点上层,如果没有设置禁止鼠标事件,点击文字将无法响应点击节点的效果,也无法拖拽节点。

    9.连线名称

    const edgesText = svg.select('g').selectAll('.edgelabel')

    .data(edges)

    .enter()

    .append('text') // 为每一条连线创建文字区域

    .attr('class', 'edgelabel')

    .attr('dx', 80)

    .attr('dy', 0);

    edgesText.append('textPath')// 设置文字内容

    .attr('xlink:href', (d, i) => { return i && '#edgepath' + i; }) // 文字布置在对应id的连线上

    .style('pointer-events', 'none')

    .text((d) => { return d && d.tag; });

    10.鼠标移到节点上有气泡提示

    nodesCircle.append('title')

    .text((node) => { // .text设置气泡提示内容

    return node.definition;

    });

    11.监听图元素的位置变化

    simulation.on('tick', () => {

    // 更新节点坐标

    nodesCircle.attr('transform', (d) => {

    return d && 'translate(' + d.x + ',' + d.y + ')';

    });

    // 更新节点文字坐标

    nodesTexts.attr('transform', (d) => {

    return 'translate(' + (d.x) + ',' + d.y + ')';

    });

    // 更新连线位置

    edgesLine.attr('d', (d) => {

    const path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;

    return path;

    });

    // 更新连线文字位置

    edgesText.attr('transform', (d, i) => {

    return 'rotate(0)';

    });

    });

    12.拖拽

    function onDragStart(d) {

    // console.log('start');

    // console.log(d3.event.active);

    if (!d3.event.active) {

    simulation.alphaTarget(1) // 设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1]

    .restart(); // 拖拽节点后,重新启动模拟

    }

    d.fx = d.x; // d.x是当前位置,d.fx是静止时位置

    d.fy = d.y;

    }

    function dragging(d) {

    d.fx = d3.event.x;

    d.fy = d3.event.y;

    }

    function onDragEnd(d) {

    if (!d3.event.active) simulation.alphaTarget(0);

    d.fx = null; // 解除dragged中固定的坐标

    d.fy = null;

    }

    const drag = d3.drag()

    .on('start', onDragStart)

    .on('drag', dragging) // 拖拽过程

    .on('end', onDragEnd);

    13.缩放

    function onZoomStart(d) {

    // console.log('start zoom');

    }

    function zooming(d) {

    // 缩放和拖拽整个g

    // console.log('zoom ing', d3.event.transform, d3.zoomTransform(this));

    g.attr('transform', d3.event.transform); // 获取g的缩放系数和平移的坐标值。

    }

    function onZoomEnd() {

    // console.log('zoom end');

    }

    const zoom = d3.zoom()

    // .translateExtent([[0, 0], [WIDTH, HEIGHT]]) // 设置或获取平移区间, 默认为[[-∞, -∞], [+∞, +∞]]

    .scaleExtent([1 / 10, 10]) // 设置最大缩放比例

    .on('start', onZoomStart)

    .on('zoom', zooming)

    .on('end', onZoomEnd);

    三、其它效果

    1.单击节点时让连接线加粗

    nodesCircle.on('click, (node) => {

    edges_line.style("stroke-width",function(line){

    if(line.source.name==node.name || line.target.name==node.name){

    return 4;

    }else{

    return 0.5;

    }

    });

    })

    2.被点击的节点变色

    nodesCircle.on('click, (node) => {

    nodesCircle.style('fill', (nodeOfSelected) => { // nodeOfSelected:所有节点, node: 选中的节点

    if (nodeOfSelected.id === node.id) { // 被点击的节点变色

    console.log('node')

    return '#36F';

    } else {

    return '#9FF';

    }

    });

    })

    四、在react中使用注意事项

    componentDidMount() {

    this.print();

    }

    print() {

    let callback = (res) => { // callback获取后台返回的数据,并存入state

    let nodeData = res.data.nodes;

    let relationData = res.data.rels;

    this.setState({

    nodeData: res.data.nodes,

    relationData: res.data.rels,

    });

    let nodes = [];

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '',

    type: (nodeData[i] && nodeData[i].type) || '',

    definition: (nodeData[i] && nodeData[i].definition) || '',

    });

    }

    let edges = [];

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '',

    target: (relationData[i] && relationData[i].end.id) || '',

    tag: (relationData[i] && relationData[i].name) || '',

    });

    }

    this.forceChart(nodes, edges); // d3力导向图内容

    };

    this.props.dispatch(getDataFromNeo4J({

    neo4jrun: 'match p=(()-[r]-()) return p limit 300',

    }, callback));

    }

    在哪里构造图因为图是动态的,如果渲染多次(render执行多次,渲染多次),不会覆盖前面渲染的图,反而会造成渲染多次,出现多个图的现象。把构造图的函数print()放到componentDidMount()内执行,则只会渲染一次。

    对节点和连线数据进行增删改操作后,需要再次调用print()函数,重新构造图。

    从哪里获取数据 数据不从redux获取,发送请求后callback直接获取。

    五、干货:d3项目查找网址

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    展开全文
  • 本篇文章主要介绍了如何在react中搭建d3力导向图,现在分享给大家,也给大家做个参考。D3js力导向图搭建d3js是一个可以基于数据来操作文档的JavaScript库。可以使用HTML,CSS,SVG以及Canvas来展示数据。力导向图能够...

    本篇文章主要介绍了如何在react中搭建d3力导向图,现在分享给大家,也给大家做个参考。

    D3js力导向图搭建

    d3js是一个可以基于数据来操作文档的JavaScript库。可以使用HTML,CSS,SVG以及Canvas来展示数据。力导向图能够用来表示节点间多对多的关系。

    实现效果:连线有箭头,点击节点能改变该节点颜色和所连接的线的粗细,缩放、拖拽。

    版本:4.X

    53ab43e0f18a594f4845dd34c458e31d.png

    安装和导入

    npm安装:npm install d3

    前端导入:import * as d3 from 'd3';

    一、完整代码import React, { Component } from 'react';

    import PropTypes from 'prop-types';

    import { connect } from 'react-redux';

    import { push } from 'react-router-redux';

    import * as d3 from 'd3';

    import { Row, Form } from 'antd';

    import { chartReq} from './actionCreator';

    import './Chart.less';

    const WIDTH = 1900;

    const HEIGHT = 580;

    const R = 30;

    let simulation;

    class Chart extends Component {

    constructor(props, context) {

    super(props, context);

    this.print = this.print.bind(this);

    this.forceChart = this.forceChart.bind(this);

    this.state = {

    };

    }

    componentWillMount() {

    this.props.dispatch(push('/Chart'));

    }

    componentDidMount() {

    this.print();

    }

    print() {

    let callback = (res) => { // callback获取后台返回的数据,并存入state

    let nodeData = res.data.nodes;

    let relationData = res.data.rels;

    this.setState({

    nodeData: res.data.nodes,

    relationData: res.data.rels,

    });

    let nodes = [];

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '',

    type: (nodeData[i] && nodeData[i].type) || '',

    definition: (nodeData[i] && nodeData[i].definition) || '',

    });

    }

    let edges = [];

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '',

    target: (relationData[i] && relationData[i].end.id) || '',

    tag: (relationData[i] && relationData[i].name) || '',

    });

    }

    this.forceChart(nodes, edges); // d3力导向图内容

    };

    this.props.dispatch(chartReq({ param: param }, callback));

    }

    // func

    forceChart(nodes, edges) {

    this.refs['theChart'].innerHTML = '';

    // 函数内其余代码请看拆解代码

    }

    render() {

    return (

    );

    }

    }

    Chart.propTypes = {

    dispatch: PropTypes.func.isRequired,

    };

    function mapStateToProps(state) {

    return {

    };

    }

    const WrappedChart = Form.create({})(Chart);

    export default connect(mapStateToProps)(WrappedChart);

    二、拆解代码

    1.组件

    整个图都将在p里绘制。

    2.构造节点和连线let nodes = []; // 节点

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '', // 节点名称

    });

    }

    let edges = []; // 连线

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '', // 开始节点

    target: (relationData[i] && relationData[i].end.id) || '', // 结束节点

    tag: (relationData[i] && relationData[i].name) || '', // 连线名称

    });

    }

    具体怎么构造依据你们的项目数据。

    3.定义力模型const simulation = d3.forceSimulation(nodes) // 指定被引用的nodes数组

    .force('link', d3.forceLink(edges).id(d => d.id).distance(150))

    .force('collision', d3.forceCollide(1).strength(0.1))

    .force('center', d3.forceCenter(WIDTH / 2, HEIGHT / 2))

    .force('charge', d3.forceManyBody().strength(-1000).distanceMax(800));

    通过simulation.force()设置力,可以设置这几种力:Centering:中心力,设置图中心点位置。

    Collision:节点碰撞作用力,.strength参数范围为[0,1]。

    Links:连线的作用力;.distance设置连线两端节点的距离。

    Many-Body:.strength的参数为正时,模拟重力,为负时,模拟电荷力;.distanceMax的参数设置最大距离。

    Positioning:给定向某个方向的力。

    通过simulation.on监听力图元素位置变化。

    4.绘制svgconst svg = d3.select('#theChart').append('svg') // 在id为‘theChart'的标签内创建svg

    .style('width', WIDTH)

    .style('height', HEIGHT * 0.9)

    .on('click', () => {

    console.log('click', d3.event.target.tagName);

    })

    .call(zoom); // 缩放

    const g = svg.append('g'); // 则svg中创建g

    创建svg,在svg里创建g,将节点连线等内容放在g内。select:选择第一个对应的元素

    selectAll:选择所有对应的元素

    append:创建元素

    5.绘制连线const edgesLine = svg.select('g')

    .selectAll('line')

    .data(edges) // 绑定数据

    .enter() // 添加数据到选择集edgepath

    .append('path') // 生成折线

    .attr('d', (d) => { return d && 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y; }) // 遍历所有数据,d表示当前遍历到的数据,返回绘制的贝塞尔曲线

    .attr('id', (d, i) => { return i && 'edgepath' + i; }) // 设置id,用于连线文字

    .attr('marker-end', 'url(#arrow)') // 根据箭头标记的id号标记箭头

    .style('stroke', '#000') // 颜色

    .style('stroke-width', 1); // 粗细

    连线用贝塞尔曲线绘制:(M 起点X 起点y L 终点x 终点y)

    6.绘制连线上的箭头const defs = g.append('defs'); // defs定义可重复使用的元素

    const arrowheads = defs.append('marker') // 创建箭头

    .attr('id', 'arrow')

    // .attr('markerUnits', 'strokeWidth') // 设置为strokeWidth箭头会随着线的粗细进行缩放

    .attr('markerUnits', 'userSpaceOnUse') // 设置为userSpaceOnUse箭头不受连接元素的影响

    .attr('class', 'arrowhead')

    .attr('markerWidth', 20) // viewport

    .attr('markerHeight', 20) // viewport

    .attr('viewBox', '0 0 20 20') // viewBox

    .attr('refX', 9.3 + R) // 偏离圆心距离

    .attr('refY', 5) // 偏离圆心距离

    .attr('orient', 'auto'); // 绘制方向,可设定为:auto(自动确认方向)和 角度值

    arrowheads.append('path')

    .attr('d', 'M0,0 L0,10 L10,5 z') // d: 路径描述,贝塞尔曲线

    .attr('fill', '#000'); // 填充颜色viewport:可视区域

    viewBox:实际大小,会自动缩放填充viewport

    7.绘制节点const nodesCircle = svg.select('g')

    .selectAll('circle')

    .data(nodes)

    .enter()

    .append('circle') // 创建圆

    .attr('r', 30) // 半径

    .style('fill', '#9FF') // 填充颜色

    .style('stroke', '#0CF') // 边框颜色

    .style('stroke-width', 2) // 边框粗细

    .on('click', (node) => { // 点击事件

    console.log('click');

    })

    .call(drag); // 拖拽单个节点带动整个图

    创建圆作为节点。

    .call()调用拖拽函数。

    8.节点名称const nodesTexts = svg.select('g')

    .selectAll('text')

    .data(nodes)

    .enter()

    .append('text')

    .attr('dy', '.3em') // 偏移量

    .attr('text-anchor', 'middle') // 节点名称放在圆圈中间位置

    .style('fill', 'black') // 颜色

    .style('pointer-events', 'none') // 禁止鼠标事件

    .text((d) => { // 文字内容

    return d && d.name; // 遍历nodes每一项,获取对应的name

    });

    因为文字在节点上层,如果没有设置禁止鼠标事件,点击文字将无法响应点击节点的效果,也无法拖拽节点。

    9.连线名称const edgesText = svg.select('g').selectAll('.edgelabel')

    .data(edges)

    .enter()

    .append('text') // 为每一条连线创建文字区域

    .attr('class', 'edgelabel')

    .attr('dx', 80)

    .attr('dy', 0);

    edgesText.append('textPath')// 设置文字内容

    .attr('xlink:href', (d, i) => { return i && '#edgepath' + i; }) // 文字布置在对应id的连线上

    .style('pointer-events', 'none')

    .text((d) => { return d && d.tag; });

    10.鼠标移到节点上有气泡提示nodesCircle.append('title')

    .text((node) => { // .text设置气泡提示内容

    return node.definition;

    });

    11.监听图元素的位置变化simulation.on('tick', () => {

    // 更新节点坐标

    nodesCircle.attr('transform', (d) => {

    return d && 'translate(' + d.x + ',' + d.y + ')';

    });

    // 更新节点文字坐标

    nodesTexts.attr('transform', (d) => {

    return 'translate(' + (d.x) + ',' + d.y + ')';

    });

    // 更新连线位置

    edgesLine.attr('d', (d) => {

    const path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;

    return path;

    });

    // 更新连线文字位置

    edgesText.attr('transform', (d, i) => {

    return 'rotate(0)';

    });

    });

    12.拖拽function onDragStart(d) {

    // console.log('start');

    // console.log(d3.event.active);

    if (!d3.event.active) {

    simulation.alphaTarget(1) // 设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1]

    .restart(); // 拖拽节点后,重新启动模拟

    }

    d.fx = d.x; // d.x是当前位置,d.fx是静止时位置

    d.fy = d.y;

    }

    function dragging(d) {

    d.fx = d3.event.x;

    d.fy = d3.event.y;

    }

    function onDragEnd(d) {

    if (!d3.event.active) simulation.alphaTarget(0);

    d.fx = null; // 解除dragged中固定的坐标

    d.fy = null;

    }

    const drag = d3.drag()

    .on('start', onDragStart)

    .on('drag', dragging) // 拖拽过程

    .on('end', onDragEnd);

    13.缩放function onZoomStart(d) {

    // console.log('start zoom');

    }

    function zooming(d) {

    // 缩放和拖拽整个g

    // console.log('zoom ing', d3.event.transform, d3.zoomTransform(this));

    g.attr('transform', d3.event.transform); // 获取g的缩放系数和平移的坐标值。

    }

    function onZoomEnd() {

    // console.log('zoom end');

    }

    const zoom = d3.zoom()

    // .translateExtent([[0, 0], [WIDTH, HEIGHT]]) // 设置或获取平移区间, 默认为[[-∞, -∞], [+∞, +∞]]

    .scaleExtent([1 / 10, 10]) // 设置最大缩放比例

    .on('start', onZoomStart)

    .on('zoom', zooming)

    .on('end', onZoomEnd);

    三、其它效果

    1.单击节点时让连接线加粗nodesCircle.on('click, (node) => {

    edges_line.style("stroke-width",function(line){

    if(line.source.name==node.name || line.target.name==node.name){

    return 4;

    }else{

    return 0.5;

    }

    });

    })

    2.被点击的节点变色nodesCircle.on('click, (node) => {

    nodesCircle.style('fill', (nodeOfSelected) => { // nodeOfSelected:所有节点, node: 选中的节点

    if (nodeOfSelected.id === node.id) { // 被点击的节点变色

    console.log('node')

    return '#36F';

    } else {

    return '#9FF';

    }

    });

    })

    四、在react中使用注意事项componentDidMount() {

    this.print();

    }

    print() {

    let callback = (res) => { // callback获取后台返回的数据,并存入state

    let nodeData = res.data.nodes;

    let relationData = res.data.rels;

    this.setState({

    nodeData: res.data.nodes,

    relationData: res.data.rels,

    });

    let nodes = [];

    for (let i = 0; i < nodeData.length; i++) {

    nodes.push({

    id: (nodeData[i] && nodeData[i].id) || '',

    name: (nodeData[i] && nodeData[i].name) || '',

    type: (nodeData[i] && nodeData[i].type) || '',

    definition: (nodeData[i] && nodeData[i].definition) || '',

    });

    }

    let edges = [];

    for (let i = 0; i < relationData.length; i++) {

    edges.push({

    id: (relationData[i] && (relationData[i].id)) || '',

    source: (relationData[i] && relationData[i].start.id) || '',

    target: (relationData[i] && relationData[i].end.id) || '',

    tag: (relationData[i] && relationData[i].name) || '',

    });

    }

    this.forceChart(nodes, edges); // d3力导向图内容

    };

    this.props.dispatch(getDataFromNeo4J({

    neo4jrun: 'match p=(()-[r]-()) return p limit 300',

    }, callback));

    }

    在哪里构造图因为图是动态的,如果渲染多次(render执行多次,渲染多次),不会覆盖前面渲染的图,反而会造成渲染多次,出现多个图的现象。把构造图的函数print()放到componentDidMount()内执行,则只会渲染一次。

    对节点和连线数据进行增删改操作后,需要再次调用print()函数,重新构造图。

    从哪里获取数据 数据不从redux获取,发送请求后callback直接获取。

    五、干货:d3项目查找网址

    D3js所有项目检索.http://blockbuilder.org/search/

    上面是我整理给大家的,希望今后会对大家有帮助。

    相关文章:

    展开全文
  • 由于性能问题的局限,将两者结合的尝试越来越多(如),本文将尝试用 D3 的力导向图 和 Three.js 和 PixiJS 结合。全文阅读完大概 5 分钟,因为你重点应该看代码。做数据可视化时,必然会考虑性能的问题。早前数据可视...
  • echarts力导向图节点折叠-附件资源
  • D3力导向图

    2019-04-18 16:17:50
    力导向图非常适合于渲染关系型信息图。 二、什么是力导向图(Force-directed)? 我们可以把整张 Network 想象成一个物理仿真系统(Simulation)。系统中的每个节点(Node)都是一个带有能量的粒子,粒子与粒子之间存在...
  • 力导布局图是一种用来呈现复杂关系网络的图表。在力导布局图中,系统中的每个节点都可以看成是一个放电粒子,粒子间存在...物理与可视化也可以擦出火花力导向图(Force-Directed Graph),又叫力学图、力导向布局图...
  • d3 力导向图

    万次阅读 2017-09-05 10:52:37
    力导向图(Force-Directed Graph),是绘图的一种算法。在二维或三维空间里配置节点,节点之间用线连接,称为连线。各连线的长度几乎相等,且尽可能不相交。节点和连线都被施加了力的作用,力是根据节点和连线的相对...
  • 最近用到d3.js中的force力导向图,想实现效果如下,所有城市节点都在可视范围内,如果超出有滚动条也可以。遇到的问题是,当节点一多,有的节点就会跑到外面去,这边是通过加大charge相互作用力,从原本的-300改为-...
  • echarts3.2.3力导向图示例

    热门讨论 2016-10-28 13:33:27
    由于echarts3与echarts2.x存在很大的不同,这里利用百度开源的echarts3.2.3做了一个的力导向图网络关系示例,详细做法可以参考我的博客文章。
  • 使用Echarts绘制力导向图

    千次阅读 2019-10-31 18:20:23
    文章目录使用Echarts绘制力导向图前言参考文档绘制力导向图扩展阅读 使用Echarts绘制力导向图 前言 本文介绍了在VS Code中使用百度Echarts来绘制力导向图(Force-directred graph)。 参考文档 [5分钟上手ECharts]...
  • d3力导向图

    2021-01-25 11:57:57
    d3力导向图 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- <script type="text/javascript" src="../d3.js"></...
  • 背景:项目 vue.js + d3 v4力导向图可以直观看出各个元素之间的相互作用力数据:{nodes:[{id:xxx, group: xx},{},...] // nodes 是每个节点 group 是聚类后的分组 为了让每个 circle 显示不同分组的颜色links:[{...
  • 力导向图Demo

    2019-07-26 23:19:25
    <html> <head> <meta charset="utf-8"> <title>力导向图</title> <style> .links line { stroke: #999;...
  • 先上图,后面再一一解释: ok,为了方便理解,这里我就没有...一、声明全局变量因为力导向图,涉及到众多节点的运动,并且在写的时候都是以callback的形式去操作这些节点,所以这里我们将这些节点声明为全局变量(应...
  • 自己写一个力导向图

    2021-04-09 17:47:49
    力导向图大家都不陌生,力导向图缺少不了力,而在数据量很大的情况下初始化节点以及对节点进行拖动时会导致整个力导图都在一直在动,密集的情况会更加严重,并且本着可以对点更好,灵活的控制,满足不同的需求,所以...
  • D3js力导向图搭建 d3js是一个可以基于数据来操作文档的JavaScript库。可以使用HTML,CSS,SVG以及Canvas来展示数据。力导向图能够用来表示节点间多对多的关系。 实现效果:连线有箭头,点击节点能改变该节点颜色和所...
  • 力导向图简介力导向图的英文名是 Force-Directed Graph,看大家都这么翻译也就这么写了。问题背景:现有若干点及其部分或全部边,求每点的位置,使其能够更美观地展现出来。将边从直线转换为适当的曲线,可以使图...
  • 大家在使用D3.js中的力导向图时,基本都会遇到动态增加节点及连线的需求,这里记录一下我的实现方式。话不多说,先放代码:Titlevar nodes = [{ name: "姓名1"},{ name: "姓名2"},{ name: "姓名3"},{ name: "姓名4"}...
  • 在D3力导向图中突出显示所选节点,其链接及其子节点我正在研究D3中的力导向图。我想通过将所有其他节点和链接设置为较低的不透明度来突出显示鼠标悬停节点,其链接及其子节点。在这个例子中,...
  • d3js关于力导向图

    2019-09-13 09:00:58
    关于d3js的力导向图说明 <html> <head> <metacharset="utf-8"> <title>力导向图</title> </head> &...
  • D3力导向地图制作

    2017-06-27 14:55:21
    制作一个中国地图的力导向地图,支持鼠标拖拽,省份作为节点,连线用三角剖分生成。访问地址:http://106.14.147.72/Graphtest/forcemap.html效果: 定义一个力导向布局、投影和地理路径生成器 创建一个...
  • 力导向图练习

    2016-09-23 07:27:11
    力导向图练习参考d3.js的学习网站:http://www.ourd3js.com/<html> <head> <meta charset="utf-8"> <title>ArrowForce_z</title> </head> .nodetext { fill: #000ff; font-size:

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 688
精华内容 275
关键字:

力导向图