zoukankan      html  css  js  c++  java
  • 基于 HTML5 WebGL 的 水泥工厂可视化系统

    前言

        如今的制造行业,基于数据进行生产策略制定与管理已经成为一种趋势,特别是 工业4.0 的浪潮下,数据战略已经成为很多制造企业的优先战略,而数据可视化以更直观的方式,帮助指导决策,成为数据分析传递信息的重要工具。通过数据可视化系统助力实现数据驱动的工业世界,为 工业4.0 提供更加灵活、敏捷、高效、个性化的数据支撑。今天就给大家带来一个采用 HightopoHT for Web 产品实现了一个水泥工厂可视化系统。

    系统预览

     

     

    本案例共有七个子系统:

    • 数据概况 -- 展示全厂年月时间单位的各项数据概况
    • 窑系统运行 -- 用窑工艺流程动画展示窑系统实时运行状态
    • 系统运行情况 -- 用动画流程图展示整个系统运行情况
    • 生料质量控制 -- 用图表和流程图展示各种生料的配比情况
    • 熟料质量控制 -- 用动画流程图展示各种熟料的配比情况
    • 煤粉质量控制 -- 用图表和流程图对煤粉质量进行监控
    • 智能物流 -- 通过 3D 场景实时监控进出厂车辆,和各项原料运输情

    子系统页面切换

          切换不同子系统时,左侧菜单和顶部标题是不需要切换的,所以我们把需要切换的内容部分别放在不同的 Block 中,Block 类型,本身不绘制任何内容,用于作为其它节点的父节点,可以与子节点同步大小,当它隐藏或显示时,所有子节点都会跟着隐藏或显示。所以当我们切换子系统时只需要控制对应的 Block 显示隐藏,而不需要去加载切换多张图纸。

    流向地图

     

        在数据概况页面中,流向地图展示年度水泥向各地区的销售情况,这里我们用 Shape 类型绘制线段来连接源地和汇地,用流动效果表示销售关系。流动效果只需引入 HT 的 ht-flow.js 插件,即可通过简单的属性设置实现,代码如下:

    // 获取线段的父节点
    this.flowParent = dm.getDataByTag('saleFlowParent');
    // 遍历得到所有线段
    this.flowParent.eachChild(child => {
        // 开启流动,设置流动样式
        child.s({
            // 开启流动
            'flow': true,
            // 设置流动组中最大元素的尺寸
            'flow.element.max': 4,
            // 设置流动组中的元素的渐变阴影中心颜色
            'flow.element.shadow.begincolor': '#49e5fe',
            // 设置流动组中的最大元素的渐变阴影尺寸
            'flow.element.shadow.max': 16,
            // 设置流动组中的元素的渐变阴影边缘颜色
            'flow.element.shadow.endcolor': 'rgba(73, 229, 254, 0)',
        });
    });

     窑系统动画

        在窑系统运行页面中,窑工艺流程动画很直观的展示了窑系统实时运行状态。画面中火焰、水和熟料在传送带上运输的动画效果,为了在性能较差的设备上也能流畅运行,我通过切换不同矢量图形的方式实现。这里用到了 HT 矢量中状态机制,先绘制多个不同的矢量组件,每个组件都可以定义状态来决定自己在哪个状态下显示,只要通过 data.s('state') 修改节点状态就可以实现如下效果:

        使用一个定时器,不断地改变节点的状态值,相关代码如下:

    this._stateTimer = setInterval(() => {
        stateNodes.forEach(node => {
            this.stateAnimation(node);
        });
    }, 180);
    //切换状态
    stateAnimation(node) {
        let stateIndex = (node.a('stateIndex') || 0) % stateEnum.length,
            state = stateEnum[stateIndex].value;
        node.s('state', state);
        node.a('stateIndex', ++stateIndex);
    }

    流程图动画

        流程图中流动线同样是使用 ht-flow.js 插件实现。由于图纸上的线段比较多,我把不同的线段分组放在不同的 Block 下,遍历其子节点设置样式,代码如下:

      //设置流动属性
      setNodeFlow (data, value) {
        if (data instanceof ht.Block) {
            data.eachChild(child => {
                this.setNodeFlow(child, value);
            });
        }
        else if (data.getDisplayName() === 'line'){
            data.s({
                'flow': value,
                'flow.element.max': 4,
                'flow.element.count': 1,
                'flow.count': 5,
                'flow.step': 10
            });
        }
    }
    //设置虚线流动属性
    setNodeDashFlow(data, value) {
        if (data instanceof ht.Block) {
            data.eachChild(child => {
                this.setNodeDashFlow(child, value);
            });
        }
        else if (data.getDisplayName() === 'border'){
            if (value) {
                data.s({
                    'shape.dash.flow': true,
                    'shape.dash': true
                });
            }
            else {
                data.s({
                    'shape.dash.flow': false,
                    'shape.dash': false
                });
            }
        }
    }

        为了使动画看起来更顺畅,我给一些节点加上透明度动画,设置节点透明度的代码如下:

    //设置节点透明度
    setNodeOpacity (data, value = 0.5) {
        if (data instanceof ht.Block) {
            data.eachChild(child => {
                this.setNodeOpacity(child, value);
            });
        }
        else {
            data.s('opacity', value);
        }
    }

        接下来只需要依次执行动画:

    //开始流程图动画
    start() {
        let {eo, eoInput, eoLine1, eoKind, eoCalu} = this;
        //工况输入透明度动画
        this.gv.enableFlow(30);
        this.setNodeOpacity(eo);
        this.setNodeFlow(eo, false);
        (new Promise((resolve, reject) => {
            this.animtion = startAnim({
                frames: 16,
                interval: 5,
                finishFunc: () => {resolve()},
                action: (v, t) => {
                    this.setNodeOpacity(eoInput, 0.5 + 0.5 * v);
                }
            });
        })).then(() => {
            //连线连线透明动画,流动
            return new Promise((resolve, reject) => {
                this.animtion = startAnim({
                    frames: 12,
                    interval: 10,
                    finishFunc: () => {
                        this.setNodeFlow(eoLine1, true);
                        this.timer = setTimeout(() => {resolve()}, 1500);
                    },
                    action: (v, t) => {
                        this.setNodeOpacity(eoLine1, 0.5 + 0.5 * v);
                    }
                });
            })
        }).then(() => {
            //软计算透明动画
            return new Promise(resolve => {
                this.animtion = startAnim({
                    frames: 16,
                    interval: 5,
                    finishFunc: () => {resolve()},
                    action: (v, t) => {
                        this.setNodeOpacity(eoKind, 0.5 + 0.5 * v);
                        this.setNodeOpacity(eoCalu, 0.5 + 0.5 * v);
                    }
                });
            });
        }).then(() => {
            //软计算透明虚线流动
            return new Promise(resolve => {
                this.setNodeDashFlow(eoKind, true);
                this.setNodeDashFlow(eoCalu, true);
                this.timer = setTimeout(() => {
                    this.setNodeDashFlow(eoKind, false);
                    this.setNodeDashFlow(eoCalu, false);
                    resolve();
                }, 3000);
            });
        }).then(() => {
            ......
        })
    }

    智能物流

        前面六个子系统均为 2D 界面,而智能物流页面则是嵌入了一个 3D 场景。实现方式是通过定义 HT 矢量 JSON 的 renderHTML 函数属性,可实现在 GraphView 拓扑图上,嵌入任意第三方 HTML DOM 元素。不过这里也要注意一点,HT 的图纸是 Canvas 实现的,renderHTML 的 DOM 元素一定在 Canvas 之上,使用 renderHTML 的 DOM 与常规 Canvas 上绘制的图元不可能有层级控制可能性。下面展示一下 renderHTML 函数属性里的代码:

    renderHTML : function (data, gv, cache) {
        // 避免重复创建g3d
        if (!cache.g3d) {
            // 创建 3D 视图组件
            var g3d = cache.g3d = new ht.graph3d.Graph3dView();
            // 布局函数,根据图元的位置信息摆放HTML元素
            g3d.layoutHTML = function () {
                gv.layoutHTML(data, g3d, true);
            };
            // 阻止事件冒泡
            g3d.getView().addEventListener('mousedown', function (event) {
                event.stopPropagation();
            });
            g3d.getView().addEventListener('touchstart', function (event) {
                event.stopPropagation();
            });
        }
        // 获取图元自定义属性sceneURL的值
        var sceneURL = data.a('sceneURL');
        // 获取图元自定义属性onPostDeserialize的值
        var onPostDeserialize = data.a('onPostDeserialize');
        // 当图元自定义属性sceneURL改变时,清除旧dataModel,反序列化新的sceneURL
        if (cache.g3d.sceneURL !== sceneURL) {
            cache.g3d.dm().clear();
            cache.g3d.sceneURL = sceneURL;
            if (sceneURL) {
                cache.g3d.deserialize(sceneURL, function (json, dm, g3d, datas) {
                    // 在反序列化后的回调函数中,执行onPostDeserialize函数
                    onPostDeserialize && onPostDeserialize(json, dm, g3d, datas);
                });
            }
        }
        return cache.g3d;
    }

         3D场景嵌入后,接下来实现水泥厂内的车辆动画。根据后台传来车辆进入工厂的数据,我们创建运载不同原料的车辆模型,让它们沿着不同的路径抵达对应的厂房。同样是用 Shape 类型事先绘制好路径,根据 Shape 的 Points 和 Segments 信息,实现车辆沿着路径行驶动画。相关代码如下:

     carAnimation(car, path, duration) {
            // 车辆行驶动画
            ht.Default.startAnim({
                duration: duration,
                easing: Easing.easeNone,
                action: function (v, t) {
                    // 设置偏移量
                    let offset = Math.floor(v * 100);
                    // 根据偏移量得到在路径上的点坐标
                    let position = ht.Default.getPercentPositionOnPoints(path.getPoints(), path.getSegments(), offset);
                    // 根据偏移量得到在路径上的点于路径切线角度
                    let angle = ht.Default.getPercentAngle(path.getPoints(), path.getSegments(), offset);
                    // 设置车辆位置坐标及旋转角度
                    car.setX(position.x);
                    car.setY(position.y);
                    car.setRotationY(Math.PI / 2 - angle);
                },
            });
        }

    总结

        工业互联网是工业发展的必经之路,我们国家是一个工业大国,正处在工业转型升级的关键时刻,面临着人工成本上升、原材料价格波动、贸易竞争日益加剧等问题,迫切需要提高效率、降低生产成本。只有坚定不移地推动工业互联网落地,加快更多企业的数字化转型和智能化改造,才有能让在全球化竞争中立于不败之地。可视化作为智能化数字化的最后一环,让复杂抽象的数据变得真正可知可感,帮助决策者发现规律,洞悉未来,为企业提速增效。

        还有更多的可视化案例可以参考:https://www.hightopo.com/demos/index.html

  • 相关阅读:
    bzoj 1017 魔兽地图DotR
    poj 1322 chocolate
    bzoj 1045 糖果传递
    poj 3067 japan
    timus 1109 Conference(二分图匹配)
    URAL 1205 By the Underground or by Foot?(SPFA)
    URAL 1242 Werewolf(DFS)
    timus 1033 Labyrinth(BFS)
    URAL 1208 Legendary Teams Contest(DFS)
    URAL 1930 Ivan's Car(BFS)
  • 原文地址:https://www.cnblogs.com/htdaydayup/p/12393328.html
Copyright © 2011-2022 走看看