索引
HT for Web
提供了弹力布局(也称为力导向布局)的功能,即根据节点之间存在互斥力,相互连接的节点间存在引力,
弹力布局运行一段时间后,整体拓扑网络结构会逐渐达到收敛稳定的平衡状态。
使用弹力布局功能需要在引入ht.js
核心库之后,再引入一个ht-forcelayout.js
的弹力布局插件库。
ForceLayout
ht.layout.ForceLayout
类提供2D
弹力布局,即3D
的xz
面布局,构造函数可传入DataModel
、GraphView
和Graph3dView
三种参数。
默认仅对未选中图元进行布局,如果构造函数参数为GraphView
和Graph3dView
时,则视图组件的isMovable
和isVisible
函数将影响图元是否可布局,
图元style
上的layoutable
属性也可设为false
阻止图元参与布局。
setLimitBounds
函数,传入{x:100, y:100, width:200, height:160}
边界结构对象,可将布局限制在指定矩形范围内。setNodeRepulsion(0~1)
改变节点间斥力,值越大节点间斥力越大,节点布局越分散。setEdgeRepulsion(0~!)
改变节点间斥力,值越大连线节点间斥力越大,连线节点布局越分散。start()
函数可启动弹力布局,调用stop()
函数可停止布局,通过isRunning()
函数可判断当前是否正在进行布局。Force3dLayout
ht.layout.Force3dLayout
类提供3D
弹力布局,构造函数可传入DataModel
和Graph3dView
两种参数。
默认仅对未选中图元进行布局,如果构造函数参数为Graph3dView
时,则视图组件的isMovable
和isVisible
函数将影响图元是否可布局,
图元style
上的layoutable
属性也可设为false
阻止图元参与布局。
setNodeRepulsion(0~1)
改变节点间斥力,值越大节点间斥力越大,节点布局越分散。setEdgeRepulsion(0~1)
改变节点间斥力,值越大连线节点间斥力越大,连线节点布局越分散。start()
函数可启动弹力布局,调用stop()
函数可停止布局,通过isRunning()
函数可判断当前是否正在进行布局。Heatmap热图技术通过众多小数据点信息,汇聚成直观可视化颜色效果,
被广泛应用于众多领域,本章节将介绍基于开源类库heatmapjs,
结合HT
实现热图呈现于GraphView
和Graph3dView
组件的方案。
heatmap
技术常运用于监控机房的环境温度,以下实现的例子将由一堆点作为热源,结合弹力布局实现热源位置动态变化的效果,
热源点信息通过heatmapjs
在内存中绘制出图像效果,最终显示到GraphView
和Graph3dView
的floor
代表地板的图元上。
Heatmapjs的使用比较简单,
详细说明文档可参见Heatmapjs官网,
为了更容易与HT
结合我们改进了heatmap.js
类库的Canvas2dRenderer
函数,使之不必传入父DOM
对象,
即config.container
参数为空时,我们将根据config
上的width
和height
参数设置canvas
对象的尺寸,
在我们的应用案例中canvas
对象只需要在内存中使用,因此无需appendChild
到父容器。
function Canvas2dRenderer(config) {
var shadowCanvas = this.shadowCanvas = document.createElement('canvas');
var canvas = this.canvas = config.canvas || document.createElement('canvas');
this._renderBoundaries = [10000, 10000, 0, 0];
canvas.className = 'heatmap-canvas';
var container = config.container;
if(container){
var computed = getComputedStyle(config.container) || {};
this._width = canvas.width = shadowCanvas.width = +(computed.width.replace(/px/,''));
this._height = canvas.height = shadowCanvas.height = +(computed.height.replace(/px/,''));
canvas.style.cssText = shadowCanvas.style.cssText = 'position:absolute;left:0;top:0;';
container.style.position = 'relative';
container.appendChild(canvas);
}else{
this._width = canvas.width = shadowCanvas.width = config.width;
this._height = canvas.height = shadowCanvas.height = config.height;
}
this.shadowCtx = shadowCanvas.getContext('2d');
this.ctx = canvas.getContext('2d');
this._palette = _getColorPalette(config);
// this._templates = {}; // move this line code to _setStyle method
this._setStyles(config);
};
另外我们发现动态更新config
的blur
参数失效,由于this._templates
缓存了久信息,
因此我们将this._templates
的初始化代码移到了setStyles
函数
_setStyles: function(config) {
this._templates = {}; // added
this._blur = (config.blur == 0)?0:(config.blur || config.defaultBlur);
if (config.backgroundColor) {
this.canvas.style.backgroundColor = config.backgroundColor;
}
this._opacity = (config.opacity || 0) * 255;
this._maxOpacity = (config.maxOpacity || config.defaultMaxOpacity) * 255;
this._minOpacity = (config.minOpacity || config.defaultMinOpacity) * 255;
this._useGradientOpacity = !!config.useGradientOpacity;
},
上例由一堆节点连线关系构成三维的网络拓扑图,其中节点代表热源,其越接近地面则地面温度越高,
这样每个节点的xz面坐标作为要传入给heatmapjs
的点xy
二维坐标信息,节点的elevation
也就是y
轴作为离地面的距离值,
距离越大转成要传入heatmapjs
的value
值越小,结合自动布局可直观的观察到节点位置动态变化时地板的温度热图变化效果。
代码核心就在重载forceLayout.onRelaxed
函数,在每次自动布局过程将所有热源节点的信息构建成heatmapjs
需要的数据,
同时通过ht.Default.setImage(‘hm-floor’, heatmap._renderer.canvas)
将热图内存中的canvas
注册成HT的图片,
而floor
地板图元绑定了hm-floor
图片,这样就实现了内存绘制的canvas
作为贴图信息动态呈现到3D
场景的效果。
上例代码还有处heatmap._renderer.canvas.dynamic = true;
的设置尤为关键,
Graph3dView
默认将图片转换成WebGL
需要的Texture
对象进行缓存,而对本例需要动态更新的情况,
则需要在注册图元对象上设置dynamic
为true
,这样Graph3dView
每次绘制会自动获取最新图片。