博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
看看这变态的自动布局
阅读量:6800 次
发布时间:2019-06-26

本文共 4071 字,大约阅读时间需要 13 分钟。

hot3.png

自动布局就是对数据元素中的节点进行定位,使节点分散在到一个比较好看的显示效果,自动布局的实质就是一种布局的算法的实现。比如TWaver默认提供圆形布局、交错布局、树形布局和弹簧布局,此外标签云、bus总线等也属于布局的应用,但需求总是变化无穷,数据结构不同,要求的呈现效果也不同,自动布局的定制在所难免,本文将介绍一种比较少见的布局效果。

 

默认的自动布局

首先我们来看看默认的自动布局的使用

var autoLayouter:AutoLayouter = new AutoLayouter(network);autoLayouter.doLayout(Consts.LAYOUT_SYMMETRY);

代码分两步,首先定义一个自动布局器关联了network组件,然后调用自动布局,进行交错布局。

可以看出,TWaver中自动布局都是通过AutoLayouter类来实现,而布局类型包括:Consts.LAYOUT_***
布局的效果如下,实际程序中可以看到布局过程的动画效果:

自动布局的实质

自动布局是自动对数据容器中所有网元进行重新定位,使节点分散开到好的显示效果,其实质是一种布局算法的实现,所以要定制自动布局就是要实现一种布局算法,以确定所有网元节点的位置。

TWaver并没有自动布局的接口,通常一个自动布局器会实现一个叫“doLayout()”的函数,以保持命名上的统一。

自动布局“接口函数”

CustomLayouter#public function getLayoutResult():Dictionary
CustomLayouter#public function doLayout():void

getLayoutResult

getLayoutResult()函数是布局算法的核心,其返回的是节点位置的计算结果,是一个Dictionary类型,< 键, 值>类型是。

doLayout

doLayout()函数包含两步,先调用getLayoutResult()得到布局位置信息,然后将这些信息,设置到网元节点上,类似下面的代码:

public function doLayout(box:ElementBox, root:IData = null):void{  var result:Dictionary = getLayoutResult(box, root);  for(var element:* in result){    var location:Point = result[element];    (element as Node).location = location;  }}

 

从上面的示例代码可以看出,实际使用中会传入一些参数,这些根据实际情况而定。此外这里也可以使用动画的平移效果,起一个Timer,动画的将节点从原始位置移动到新的位置。

开始定制

下面开始布局算法,这里我们将布出下面的效果,整体是一个树结构,从左到右四层,最后一层使用Bus布局:

因为只是一个示例,布局实现不可能尽善尽美,所以只提供些实现的思路,算是抛砖引玉,作为参考:

整理数据结构

首先理清数据的结构,本例是一个树状布局,具有固定的四层结构,故本例将每一层的节点找出来,如第一层一个节点,第二层四个节点,第三层十二个节点,第四层可能右八十多个节点。

本例中使用了dataBox的广度遍历,每遍历完一层,就对这层上的节点作布局,这样一次遍历完,布局也做完,也就是说“整理数据结构”和“分别对每层布局”是同时进行的,但这并不是很好的示范,通常还是老老实实先整理数据的结构,甚至做一些模型的封装了表示这些模型,然后再做布局。

 

使用dataBox的广度遍历,每遍历完一层,就对这层上的节点作布局:

 

public function getLayoutResult(box:ElementBox, root:IData = null):Dictionary{	var result:Dictionary = new Dictionary();	function _calculateLocations(queue:Array, layer:int):void{		var sum:int = queue.length;		if(sum == 0){			return;		}		queue.forEach(function(node:IData, index:int, a:*):void{			var subIndex:int = index;			var parentPoint:Point = null;			var subSum:int = sum;			if(node.parent){				subIndex = node.parent.children.getItemIndex(node);				parentPoint = result[node.parent];				subSum = node.parent.childrenCount;			}			var location:Point = calculateLocation(node, layer, index , sum, subIndex, subSum, parentPoint);			result[node] = location;		});	};	var parent:IData = null;	var layer:int = 0;	var queue:Array = new Array();	box.forEachByBreadthFirst(function(node:IData):void{		if(!(node is Node)){			return;		}		if(node.parent != parent){			parent = node.parent;			var l:int = 0;			var p:IData = node.parent;			while(p){				l++;				p = p.parent;			}			if(l != layer){				_calculateLocations(queue, layer);				layer++;				queue = new Array();			}		}		queue.push(node);	}, root);	_calculateLocations(queue, layer);	return result;}

 

分别对每层布局

有了上面这些信息,就很方便对各层作不同的布局:第一层到第四层,从左到右排列,每层节点从上到下排列,最后一层水平排列,本例中实现布局的函数是calculateLocation(…),传入的参数包含了该节点布局相关的信息(所在层,在同层的位置,该层总共有多少节点,在其父节点的位置,其父节点所有的孩子数,父节点的布局位置)

 

public function calculateLocation(node:IData, layer:int, index:int, sum:int, subIndex:int, subSum:int, parentPoint:Point = null):Point

var maxHeight:int = 700;var startX:int = 10;var startY:int = 10;public function calculateLocation(node:IData, layer:int, index:int, sum:int, subIndex:int, subSum:int, parentPoint:Point = null):Point{	var x:int = startX;	var y:int = startY;	var hGap:int = getHorizontalGap(layer);	if(layer < 3){		x = parentPoint ? parentPoint.x + hGap : startX;		y = startY + getVerticalGap(layer, sum) * (index + 0.5);	}else if(layer == 3 && parentPoint){		x = parentPoint.x + hGap + subIndex/2 * 50;		y = parentPoint.y + ((subIndex % 2 == 0 ) ? 15 : -15);	}	return new Point(x, y);}public function getHorizontalGap(layer:int):int{	return layer == 3 ? 90 : 150;}public function getVerticalGap(layer:Number, sum:Number):Number{	return Math.max(maxHeight/(sum + 0.5), 75);}

连线样式的定制

本例中连线样式的配置也是关键,对于第四层Bus布局的呈现主要通过正交连线样式来体现,所以在数据添加时,对第四层的连线设置如下:

var link:Link = new Link(parent, node);link.setStyle(Styles.LINK_TYPE, Consts.LINK_TYPE_HORIZONTAL_VERTICAL);link.setStyle(Styles.LINK_CORNER, Consts.LINK_CORNER_NONE);box.add(link);

转载于:https://my.oschina.net/monolog/blog/404762

你可能感兴趣的文章
KeyMob--后者居上的移动广告聚合平台
查看>>
eclipse maven source 乱码
查看>>
Linux系统下UDP发送和接收广播消息小例子
查看>>
每天尝试改变一点点!
查看>>
KNN(K-Nearest Neighbor)最邻近规则分类
查看>>
IntelliJ IDEA 2016.1破解码一枚
查看>>
metasploit ***测试笔记(meterpreter篇)
查看>>
HTTP基础
查看>>
JavaSE学习笔记(五)——类与对象
查看>>
Android之高仿飞鸽传输热点创建与搜索模块
查看>>
Struts2、Spring和Hibernate应用实例(中)
查看>>
[转]MYSQL性能优化分享(分库分表)
查看>>
用php实现异步执行任务的队列(一)
查看>>
AngularJS表单验证操作例子分享
查看>>
RabbitMQ 的安装与工作模式
查看>>
视图的跳转,ViewController的使用 。试图出现启动消失过程
查看>>
博科300光纤交换机配置手册/操作方法/密码设置/用户指南大全
查看>>
HTML Dom
查看>>
Linux下为PHP添加扩展库的方法
查看>>
HBase(四):HBase API判断表是否存在,结果问题爆棚。。
查看>>