Skip to content
目录

热力图组件Heatmap

热力图组件 Heatmap 是一种通过颜色渐变来展示数据分布和密度的可视化工具,常用于展示机房温度分布(温度云图)等情况,以下均以 温度云图 为例进行讲解演示。 Heatmap 组件一般挂载在 楼层Floor 或者 园区Campus ,且 Heatmap 组件是自动挂载组件,不需要手动添加。

数据点位

GlowJS约定使用 数据点位 标签来标记温度云图的设备点位,一般在机柜模型上设置该标签。数据点位可以用来绑定温度值。只要场景层级中存在带有 数据点位 标签的物体实体,那么该场景层级就会自动挂载 Heatmap 组件。

热力图

Heatmap 组件对象有一个只读实例成员 points,该成员是一个 实体 对象数组,数组中的每个元素表示一个数据点位。

热力图类型

热力图类型使用枚举类型 HeatmapType 来表示,支持以下类型:

  • HeatmapType.Horizontal:水平图

  • HeatmapType.Vertical:垂直图

Heatmap 组件对象有一个实例属性 heattype ,该属性用于设置热力图类型。

typescript
heatmap.heattype = GLOW.HeatmapType.Horizontal;

注意:其中水平图是根据机房房间生成的,因此不能将房间地板删除,但可以隐藏房间地板,否则将引发错误

图层配置

使用静态成员 Heatmap.layers 来设置图层, layers 是一个对象数组,每个对象表示一个图层,包含以下属性:

  • name:图层名称

  • offsetY:离地高度

layers 默认包含0个元素,需要手动添加。一般情况下,为了生成温度云图,会在机柜的上、中、下位置各安装一个温度传感器(共3各)采集温度数据,有时为了区别机柜前后的温度会在机柜的上、中、下位置的前、后面各安装一个温度传感器(共6个)。以下是一个配置示例:

typescript
GLOW.Heatmap.layers.push({ name: '上层', offsetY: 1.7 });
GLOW.Heatmap.layers.push({ name: '中层', offsetY: 1 });
GLOW.Heatmap.layers.push({ name: '下层', offsetY: 0.3 });

注意:

  • ①当添加了3个图层时,一个 数据点位 可以绑定3个温度值。

  • ②当一个机柜安装了6个温度传感器时,如果只在机柜模型上添加 数据点位 标签,显然无法满足需求了。此时可以使用专门的 数据点位 模型(位于 其它/杂项 中),分别在机柜的前、后面各摆放一个该模型即可。

热力图

Heatmap 组件对象有一个实例属性 layerName ,当生成水平图时,需要设置该属性来指定图层名称;当生成垂直图时,该属性无效。

typescript
heatmap.layerName = '上层';

数值限定

使用静态成员 Heatmap.minHeatmap.max 来设置数值限定, minmax 是一个数字,表示值的最小值和最大值。最小值默认为 18 ,最大值默认为 30

typescript
GLOW.Heatmap.min = 15;
GLOW.Heatmap.max = 35;

生成温度云图步骤

参考 温度云图完整示例

热力图

完整示例代码:

typescript
let app: GLOW.App;
let timeId: number = -1;

/**
 * 入口函数
 * @param container DIV容器
 */
function main(container: HTMLDivElement): void {
    //设置云图图层
    GLOW.Heatmap.layers.push({ name: '上层', offsetY: 1.7 });
    GLOW.Heatmap.layers.push({ name: '中层', offsetY: 1 });
    GLOW.Heatmap.layers.push({ name: '下层', offsetY: 0.3 });
    //设置值范围
    GLOW.Heatmap.min = 18;
    GLOW.Heatmap.max = 30;

    //创建一个GlowJS App实例
    app = new GLOW.App({
        container,
        projectFile: 'glowjs/project/file/2f66ef33c2bdfa9ac2d19eb8522b4157.json'
    });

    app.once(GLOW.EventType.LevelCreate, () => {
        let btn_H1 = createButton("水平图_上层", '20px');
        btn_H1.onclick = () => onShowClick(GLOW.HeatmapType.Horizontal, '上层');

        let btn_H2 = createButton("水平图_中层", '150px');
        btn_H2.onclick = () => onShowClick(GLOW.HeatmapType.Horizontal, '中层');

        let btn_H3 = createButton("水平图_下层", '280px');
        btn_H3.onclick = () => onShowClick(GLOW.HeatmapType.Horizontal, '下层');

        let btn_V = createButton('垂直图', "410px");
        btn_V.onclick = () => onShowClick(GLOW.HeatmapType.Vertical);

        let btn_T = createButton('显隐值', "500px");
        btn_T.onclick = () => {
            let heatmap = app.levelMgr.current.getComponent(GLOW.Heatmap);
            heatmap.showValues = !heatmap.showValues;
        }

        let btn_C = createButton('清理', "600px");
        btn_C.onclick = () => onCleanClick();
    });

    //调用App实例的加载方法
    app.load();
}

function onCleanClick(): void {
    if (timeId !== -1) {//如果已有定时器,则先清理
        clearTimeout(timeId);
        timeId = -1;
    }
    let heatmap = app.levelMgr.current.getComponent(GLOW.Heatmap);
    heatmap.clean();
}

async function onShowClick(type: GLOW.HeatmapType, layerName?: string): Promise<void> {
    if (timeId !== -1) {//如果已有定时器,则先清理
        clearTimeout(timeId);
        timeId = -1;
    }

    let heatmap = app.levelMgr.current.getComponent(GLOW.Heatmap);
    heatmap.heattype = type;//设置云图类型
    if (layerName) heatmap.layerName = layerName;//设置图层名称
    loop();//启动定时器循环渲染
    await renderOnce();//立即渲染一次
}

function loop(): void {//循环渲染
    timeId = setTimeout(async () => {
        await renderOnce();
        loop();
    }, 3000);
}

async function renderOnce(): Promise<void> {//渲染单次
    let heatmap = app.levelMgr.current.getComponent(GLOW.Heatmap);
    for (let p of heatmap.points) {
        p.userData['上层'] = newValue();
        p.userData['中层'] = newValue();
        p.userData['下层'] = newValue();
    }
    await heatmap.render();
}

function newValue(): number {//模拟生成一个新值
    return 10 + Math.random() * 30;
}

function createButton(text: string, left: string): HTMLButtonElement {
    let btn: HTMLButtonElement = document.createElement('button');
    btn.textContent = text;
    btn.style.position = 'absolute';
    btn.style.left = left;
    btn.style.top = '20px';
    btn.style.padding = '5px 10px';
    btn.style.cursor = 'pointer';
    document.body.append(btn);
    return btn;
}

以下是生成温度云图的步骤:

  1. 配置图层,一般三层。
typescript
GLOW.Heatmap.layers.push({ name: '上层', offsetY: 1.7 });
GLOW.Heatmap.layers.push({ name: '中层', offsetY: 1 });
GLOW.Heatmap.layers.push({ name: '下层', offsetY: 0.3 });
  1. 配置数值限定,一般保持默认值即可。
typescript
GLOW.Heatmap.min = 18;
GLOW.Heatmap.max = 30;
  1. 设置温度云图类型。
typescript
heatmap.heattype = GLOW.HeatmapType.Horizontal;

4.设置图层名称。

typescript
heatmap.layerName = '上层';//水平图需要设置
heatmap.layerName = '';//垂直图设置为空字符串即可

5.设置是否显示数值。默认不显示,如果不需要显示数值,则可以不设置或者显式设置为false。

typescript
heatmap.showValues = true;

6.设置 数据点位 实体对象的温度值。这里需要用到实体对象的 userData 属性,该属性是一个对象,用图层名称作为键,用温度值作为值。

typescript
entity.userData['上层'] = 15;
entity.userData['中层'] = 32;
entity.userData['下层'] = 27.8;

7.调用渲染方法render(),该方法是一个异步方法。

typescript
await heatmap.render();

8.循环刷新。通过定时器循环执行步骤6、7,即可实现温度云图的动态刷新。

9.退出云图。应该先清理定时器,然后调用 heatmap.clean() 方法来清除云图。

typescript
clearTimeout(timeId);
timeId = -1;
heatmap.clean();

技术支持:13352865103(柯工,微信同号);18688783852(柯工)