vue族谱架构_vue.js中使用d3.js画家谱关系图
项目中需要做个家谱图,网上查了好多资料没找到合适的,就自己写个简单的,方便以后查看,附上效果图
首先展示父亲、配偶、子女,三代人信息,然后选择其他人可以展开他的三代关系。如下图
下面是代码,这个关系图还只是个初稿,里有些逻辑不全,其中母亲这个通过父亲展开就不合适。以后有机会再完善吧。
height='250'
highlight-current-row
@current-change="handleCurrentChange"
:data='nodes'>
prop='id'
label='id'
width='50'>
prop='name'
label='姓名'>
height='250'
:data='links'>
prop='srcId'
label='源id'
width='50'>
prop='toId'
label='目标id'>
label='关系'>
{{ scope.row.type | toCn }}
import * as d3 from 'd3';
let width_ = 60;
export default {
data () {
return {
srcNode: null,
svg: null,
nodes: [
{id: '0', name: '张三'},
{id: '1', name: '张父'},
{id: '2', name: '张母'},
{id: '3', name: '张三妻'},
{id: '4', name: '张大'},
{id: '5', name: '张小'},
{id: '6', name: '张小妻'},
{id: '7', name: '张小小'},
{id: '8', name: '张三妻父'},
{id: '9', name: '张三妻母'},
{id: '10', name: '张三妻弟'}
],
links: [
{srcId: '0', toId: '1', type: 0}, // 0 父子
// {srcId: '0', toId: '2', type: 1}, // 1 母子
{srcId: '1', toId: '2', type: 2}, // 2 配偶
{srcId: '0', toId: '3', type: 2}, // 2 配偶
{srcId: '0', toId: '4', type: 3}, // 子女
{srcId: '0', toId: '5', type: 3}, // 子女
{srcId: '5', toId: '6', type: 2}, // 配偶
{srcId: '5', toId: '7', type: 3}, // 子女
{srcId: '3', toId: '8', type: 0}, // 父
{srcId: '8', toId: '9', type: 2}, // 配偶
{srcId: '8', toId: '10', type: 3} // 子女
],
drag: false
};
},
filters: {
toCn (src) {
let res = ['父子', '母子', '配偶', '子女'];
return res[src];
}
},
methods: {
handleCurrentChange (row) {
this.srcNode = row;
// 查找中心点连线关系 srcId = 0
let srcId = row.id;
let srcNode = this.nodes.filter(n => n.id === srcId)[0];
// 获取与此节点关系点
let links = this.links.filter(l => l.srcId === srcId);
let otherlinks = this.links.filter(l => l.toId === srcId).map(l => {
let link = {};
if (l.type === 3) { // 子女 -> 父子
link.type = 0;
} else if (l.type === 0) { // 父女 -> 子女
link.type = 3;
} else {
link.type = l.type;
}
link.srcId = l.toId;
link.toId = l.srcId;
return link;
});
links.push(...otherlinks);
// 计算节点坐标
let nodes_ = this.convert(srcNode, links);
let that = this;
// 设置画布
let width = 1000;
let height = 720;
// console.log(d3.select('.testd3')[0].innerHTML);
d3.select('.testd3').selectAll('*').remove();
// 画中心点
let svg = d3.select('.testd3').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(40,0)');
var drag = d3.behavior.drag()
.on('drag', function(d) {
d3.select(this)
.attr('transform', 'translate(' + (d3.event.x - 30) + ',' + (d3.event.y - 30) + ')')
.append('rect')
.attr('x', d.x = d3.event.x - 30)
.attr('y', d.y = d3.event.y - 30);
// 线条
svg.selectAll(`.link-${d.id}`).attr('d', function(dd) {
return that.getPath(d, dd);
});
});
that.drag = drag;
// 画线
this.drawLinks(svg, links);
// 画点
console.log('nodes_', nodes_);
this.drawNodes(svg, nodes_);
},
// 转换
convert (srcNode, links) {
let nodes = [];
let map = new Map();
// 子女个数
let childsize = links.filter(l => l.type === 3).length;
// 子女开始位置
let start = -(childsize - 1) * width_;
if (srcNode.x === undefined) { // 默认坐标
srcNode.x = 150;
srcNode.y = 150;
}
map.set(srcNode.id, srcNode);
let {x, y} = srcNode;
links.forEach(l => {
if (l.type === 0) { // 父子
map.set(l.toId, {x: x, y: y - width_ * 2, type: l.type});
}
if (l.type === 1) { // 母子
map.set(l.toId, {x: x + width_ * 2, y: y - width_ * 2, type: l.type});
}
if (l.type === 2) { // 配偶
map.set(l.toId, {x: x + width_ * 2, y: y, type: l.type});
}
if (l.type === 3) { // 子女
map.set(l.toId, {x: x + start, y: y + width_ * 2, type: l.type});
start = start + width_ * 2;
}
});
this.nodes.forEach(n => {
let m = map.get(n.id);
if (m) {
n['x'] = n.x || m.x;
n['y'] = n.y || m.y;
n['type'] = m.type;
nodes.push(n);
}
});
return nodes;
},
getPath (move, stas) {
// 获取对方坐标
let srcId = stas.srcId;
let flag = false;
if (move.id === stas.srcId) {
srcId = stas.toId;
flag = true;
}
let path;
// 源
let {x, y} = this.nodes.filter(n => n.id === srcId)[0];
if (stas.type === 0) { // 父子
if (flag) {
path = `M${x + width_ / 2} ${y}
L${x + width_ / 2} ${y + width_ * 1.5}
L${move.x + width_ / 2} ${move.y - width_ / 2}
L${move.x + width_ / 2} ${move.y}`;
} else {
path = `M${x + width_ / 2} ${y}
L${x + width_ / 2} ${y - width_ / 2}
L${move.x + width_ / 2} ${move.y + width_ * 1.5}
L${move.x + width_ / 2} ${move.y}`;
}
}
if (stas.type === 2 || stas.type === 1) { // 配偶
let w_ = move.x > x ? width_ : -width_;
let padding = move.x > x ? -width_ / 2 : width_ * 1.5;
if (flag) {
path = `M${x + width_ / 2 + w_ / 2} ${y + width_ / 2}
L${move.x + padding} ${y + width_ / 2}
L${move.x + width_ / 2 - w_ / 2} ${move.y + width_ / 2}`;
} else {
path = `M${x + width_ / 2 + w_ / 2} ${y + width_ / 2}
L${move.x + padding} ${y + width_ / 2}
L${move.x + width_ / 2} ${move.y + width_ / 2}`;
}
}
if (stas.type === 3) { // 子女
if (flag) {
path = `M${x + width_ / 2} ${y + width_}
L${x + width_ / 2} ${y - width_ / 2}
L${move.x + width_ / 2} ${move.y + width_ * 1.5}
L${move.x + width_ / 2} ${move.y + width_}`;
} else {
path = `M${x + width_ / 2} ${y + width_}
L${x + width_ / 2} ${y + width_ * 1.5}
L${move.x + width_ / 2} ${move.y - width_ / 2}
L${move.x + width_ / 2} ${move.y + width_}`;
}
}
return path;
},
drawNode (svg, node) {
let node_ = svg.selectAll(`.node-${node.id}`)
.data([node])
.enter()
.append('g')
.attr('class', `node-${node.id}`)
.attr('transform', function(d) {
return 'translate(' + (d.x) + ',' + (d.y) + ')';
})
.on('dblclick', (d) => {
let links = this.links.filter(l => l.srcId === d.id);
if (links.length === 0) {
this.$message('没有关联数据');
return;
}
let nodes2 = this.convert(d, links);
this.drawLinks(svg, links);
this.drawNodes(svg, nodes2);
})
.on('mouseover', function(d) {
d3.select(this).select('rect')
.attr('stroke', '#FFCC33')
.attr('stroke-width', 3); // 设置边框
})
.on('mouseout', function(d) {
d3.select(this).select('rect')
.attr('stroke-width', 0); // 取消边框
})
.call(this.drag);
node_.append('rect')
.attr('width', 60)
.attr('height', 60)
.attr('x', 0)
.attr('y', 0)
.attr('style', (d) => {
return (d.type === 1 || d.type === 2) ? 'fill:#FFAD5B;' : 'fill:#35AD5B;';
});
node_.append('text')
.attr('dx', function(d) {
return 30;
})
.attr('dy', 30)
.style('text-anchor', function(d) {
return 'middle';
})
.style('fill', '#fff')
.text(function(d) {
return d.name;
});
},
drawNodes (svg, nodes) {
nodes.forEach(n => {
this.drawNode(svg, n);
});
},
// 添加链接
drawLinks (svg, linksData) {
let that = this;
linksData.forEach(l => {
let classFlag = l.srcId > l.toId ? `${l.srcId}-${l.toId}` : `${l.toId}-${l.srcId}`;
svg.selectAll(`.link-${classFlag}`)
.data([l])
.enter()
.append('path')
.attr('class', d => {
return `link-${d.srcId} link-${d.toId} link-${classFlag}`;
})
.attr('d', function(d) {
let node = that.nodes.filter(n => n.id === d.toId)[0];
return that.getPath(node, d);
})
.attr('style', function() {
return 'stroke:#F7881F';
});
});
}
},
mounted() {
}
};
[class^=link] {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.demo {
width: 100%;
height: 100%;
}
.left {
float: left;
width: 30%;
}
.testd3 {
float: left;
width: 70%;
}
vue族谱架构_vue.js中使用d3.js画家谱关系图相关推荐
- D3.js的v5版本入门教程(第一章)—— 如何在项目中使用D3.js
D3.js的v5版本入门教程(第一章) 1.需要的一些工具 这个其实随便!最简单的就是建一个.txt文件就可以敲起代码来!作者本人用的是myeclipse(主要需要安装tomcat),因为写的是前端, ...
- 使用antV-G6在angualr中画树形关系图
使用antV-G6在angualr中画树形关系图(流量追踪图) 公司有个需求就是既要呈现出每个节点之间的关系(图里面需要带箭头,为了表现出流向关系),又要排版呈现出树状结构,也就是说是具备层次关系的 ...
- 数学建模中如何用 matlab画漂亮的图(一)
数学建模中如何用 matlab画漂亮的图(二维图形) 1 plot绘图命令*** 1.1 plot(x) 当x为实向量时,plot(x)绘制出的曲线,横坐标为该向量的下表,纵坐标为每一个下表位置所对应 ...
- vue族谱架构_从零开始做Vue前端架构(1)
前言 想想也已经做过不少架构的项目了,有基于vue,基于react,基于thinkPHP,基于laravel的. 做多了,也就对现有的架构有各种想法,有好的,有坏的,总之,用起来还是不爽.vue-cl ...
- 在vue文件引入echarts_vue文件中使用echarts.js的两种方式
最近工作中需要用到echarts,由于项目是用的vue-cli开发的.在网上搜到vue中合成了vue-echarts,但是不想使用vue中规定好的数据格式,于是就自己做了一个vue项目引用原生echa ...
- vue族谱架构_【Vue】谈Vue的依赖追踪系统 ——搞懂methods watch和compute的区别和联系...
之前一直在博客园写作,最近几天才开的知乎专栏,才疏学浅, 谬误之处请不吝于评论区指教,谢谢大家.从作用机制和性质上看待methods,watch和computed的关系 watch和computed的 ...
- js:js中加载js文件
这个问题,之前没怎么想过,因为现在大部分时间我们都在搞 react.vue + webpack 这种有模块化的,所以基本上用 es module 就可以. 一般最终形态都是 html 引入 scrip ...
- js中使用template.js插件
$.ajax({url:'http://10.162.12.85:8080/api/info?code=bingbing2&type=1',type:'get',dataType: 'json ...
- JS中包含其它JS文件
2008-01-06 12:15 把下面的代码保存为同一目录下a.htm, a.js, b.js三个文件,然后打开a.htm看效果. a.htm的内容 ------------------------ ...
最新文章
- 剑指offer(Java实现) 从上往下打印二叉树
- struts实战--登录功能实现
- (WPF, MVVM) Event 处理
- 在jsp中应如何避免,request.getContextPath();等get报错问题
- 如何给视频中插入视频,字幕,以及去掉前后广告
- java多功能钟_Java 11将包含更多功能
- 689 Maximum Sum of 3 Non-Overlapping Subarrays
- IO编程——转自廖雪峰博客
- Android ViewDragHelper的简单分析及应用(二)
- 偶遇 649453.sys / Adware.Cdn / Hacktool.Rootkit
- 帝国网站mysql 数据库开发_帝国cms操作数据库函数范例(二次开发)
- PHP二次元风格发卡系统源码荔枝发卡网
- 2019 ICPC 上海网络赛 K. Peekaboo
- The Shawshank Redemption-3
- 2014年10月30日 1、完成AHC合并部分,调试通过代码
- 芝麻信用网页api php,谈谈php对接芝麻信用踩的坑
- ios图片放大之后如何不模糊_如何放大图片而不模糊
- html倒计时10s,vue做30s倒计时,在最后10s倒数的时候有个放大的效果
- 计算机动画技术的应用领域,3D动画技术的应用领域
- 什么是桑基图,桑基图又有什么作用?
热门文章
- elasticSearch常见问题答疑
- (精华)2020年8月22日 ABP vNext Web应用ABP
- HDU6194 后缀数组的应用
- 吴恩达深度学习相关资源下载地址(蓝奏云)
- Rancher 2.2 GA:企业进入应用跨多K8S集群、混合云部署新时代
- RabbitMQ简介及简单使用
- iled to read key AndroidDebugKey from store “D:\路经\.android\debug.keystore“: Invalid keystore format
- 下载安装Java运行环境
- 绘图软件origin使用总结
- Oracle 11g 的下载与安装