HT for Web 弹力布局手册

索引


概述

HT for Web提供了弹力布局(也称为力导向布局)的功能,即根据节点之间存在互斥力,相互连接的节点间存在引力, 弹力布局运行一段时间后,整体拓扑网络结构会逐渐达到收敛稳定的平衡状态。

使用弹力布局功能需要在引入ht.js核心库之后,再引入一个ht-forcelayout.js的弹力布局插件库。

弹力布局

ForceLayout

ht.layout.ForceLayout类提供2D弹力布局,即3Dxz面布局,构造函数可传入DataModelGraphViewGraph3dView三种参数。 默认仅对未选中图元进行布局,如果构造函数参数为GraphViewGraph3dView时,则视图组件的isMovableisVisible函数将影响图元是否可布局, 图元style上的layoutable属性也可设为false阻止图元参与布局。

Force3dLayout

ht.layout.Force3dLayout类提供3D弹力布局,构造函数可传入DataModelGraph3dView两种参数。 默认仅对未选中图元进行布局,如果构造函数参数为Graph3dView时,则视图组件的isMovableisVisible函数将影响图元是否可布局, 图元style上的layoutable属性也可设为false阻止图元参与布局。

热图应用

Heatmap热图技术通过众多小数据点信息,汇聚成直观可视化颜色效果, 被广泛应用于众多领域,本章节将介绍基于开源类库heatmapjs, 结合HT实现热图呈现于GraphViewGraph3dView组件的方案。

heatmap技术常运用于监控机房的环境温度,以下实现的例子将由一堆点作为热源,结合弹力布局实现热源位置动态变化的效果, 热源点信息通过heatmapjs在内存中绘制出图像效果,最终显示到GraphViewGraph3dViewfloor代表地板的图元上。

Heatmapjs的使用比较简单, 详细说明文档可参见Heatmapjs官网, 为了更容易与HT结合我们改进了heatmap.js类库的Canvas2dRenderer函数,使之不必传入父DOM对象, 即config.container参数为空时,我们将根据config上的widthheight参数设置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);
};

另外我们发现动态更新configblur参数失效,由于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轴作为离地面的距离值, 距离越大转成要传入heatmapjsvalue值越小,结合自动布局可直观的观察到节点位置动态变化时地板的温度热图变化效果。

代码核心就在重载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对象进行缓存,而对本例需要动态更新的情况, 则需要在注册图元对象上设置dynamictrue,这样Graph3dView每次绘制会自动获取最新图片。


欢迎交流 service@hightopo.com