canvas画一个企业结构图

描述
有时候我们根据需求需要canvas或svg画一些效果图,本案例是画企业树形图,希望各位大大支持与意见。不用废话先上图。

效果图
在这里插入图片描述

github地址
https://github.com/callBackFnYDG/EnterpriseStructureTree

案例实现原理
首先我们定义出,节点宽度,节点高度,节点间距离,父子节点间距离

var nodeWidth = 100; // 节点宽度
var nodeHeight = 50; // 节点高度
var heightSpace = 200; // 父子节点间距离
var nodeSpace = 20; // 节点间距离
var treeSpace = nodeWidth + nodeSpace;  // 节点总宽度

以上我们可以得到树最底层没有子节点的宽高节点间距,但是我们往上走的话父节点如果还用这个宽度计算节点位置 那么有可能会出现某些子节点叠加,解决方案,我们用回调函数从最底层计算宽度直至最顶层。

// 计算宽度
var traverse = function(node) {
	var nodeWidth = 0
	var childNodes = node.children ? node.children : [];
	var leftWidth = 0
	var rightWidth = 0
	
	for (var i = 0; i < childNodes.length; i++) {
		
		var data = traverse(childNodes[i]);
		if (!data.nodeWidth) {
			data.nodeWidth = treeSpace
		}
		if (!data.leftWidth) {
			data.leftWidth = treeSpace / 2
		}
		if (!data.rightWidth) {
			data.rightWidth = treeSpace / 2
		}
		
		if (i % 2 == 1) {
			leftWidth += data.nodeWidth
		} else {
			rightWidth += data.nodeWidth
		}
		nodeWidth += data.nodeWidth
	}
	node.nodeWidth = nodeWidth
	node.leftWidth = leftWidth
	node.rightWidth = rightWidth
	return node
};

以上出现 leftWidthrightWidth 因为我计算节点位置的时候是根据上一个节点位置计算的,第一个节点位置是根据当前兄弟节点是否是双数,是->第一二节点特殊(与父节点x轴相差 leftWidth,或者 rightWidth),否-> 第一个节点特殊(与父节点x轴一致)。之后的节点根据前一个节点计算位置 公式大概为

// 左侧节点=>计算方向为水平方向 x
Xn = X(n-2) - ( X(n-2).leftWidth + Xn.rightWidth)
// 右侧节点=>计算方向为水平方向 x
Xn = X(n-2) + ( X(n-2).rightWidth + Xn.leftWidth)

// 计算位置
var position = function(node) {
	var pos = node.position ? node.position : [0, 0];
	var childNodes = node.children ? node.children : [];
	var bol = childNodes.length % 2 == 1
	var min = 0
	var max = 0
	
	for (var i = 0; i < childNodes.length; i++) {
		
		var vector = i % 2 == 1 ? -1 : 1;
		var y = pos[1] + heightSpace
		
		// 单数情况下 第一项特殊
		if (bol && i == 0) {
			childNodes[i].position = [pos[0], y]
		} 
		// 双数情况下 前两项特殊
		else if (!bol && (i == 0 || i == 1)) {
			var LEFT_OR_RIGHT_WIDTH = i == 1 ? childNodes[i].rightWidth : childNodes[i].leftWidth
			childNodes[i].position = [pos[0] + vector * LEFT_OR_RIGHT_WIDTH , y]
		}
		// 其它情况下都一样
		else {
			var index = i < 2 ? 0 : i - 2;
			var n = childNodes[index]
			var w = i % 2 == 1 ? (n.leftWidth + childNodes[i].rightWidth) : (n.rightWidth + childNodes[i].leftWidth);
			var x = n.position[0] + w * vector;
			childNodes[i].position = [x, y]
		}
		// 计算中间那条线的距离
		if (i == 0) {
			max = childNodes[i].position[0]
			min = childNodes[i].position[0]
		}
		if (childNodes[i].position[0] > max) max = childNodes[i].position[0]
		if (childNodes[i].position[0] < min) min = childNodes[i].position[0]
		// 父节点位置
		childNodes[i].parentPosition = pos
		// 父节点
		childNodes[i].parentNode = node
		var data = position(childNodes[i]);
	}
	
	node.lineWidth = [min, max]
	node.position = pos
	nodes.push(node)
	return node
}

有了每个节点位置节点所占用宽度之后剩下的就只有绘图了,可以根据这个计算得到的画布上的节点画自己想要的线和节点的样式。
特别说明
1,如果需要祖先元素节点计算方式和子元素节点计算方式一致
2,计算时先计算的节点宽度,left宽度,right宽度后计算节点二维坐标位置,因此用到两次循环,各位大大有没有想法可以用一个循环解决
3,本案例一开始就没有考虑用d3,hcharts,echarts。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值