`
xhload3d
  • 浏览: 206023 次
社区版块
存档分类
最新评论

HT图形组件设计之道(二)

阅读更多

上一篇我们自定义CPU和内存的展示界面效果,这篇我们将继续采用HT完成一个新任务:实现一个能进行展开和合并切换动作的刀闸控件。对于电力SCADA和工业控制等领域的人机交互界面常需要预定义一堆的行业标准控件,以便用户能做可视化编辑器里,通过拖拽方式快速搭建具体电力网络或工控环境的场景,并设置好设备对应后台编号等参数信息,将拓扑图形与图元信息一并保存到后台,实际运行环境中将打开编辑好的网络拓扑图信息,连接后台实时数据库,接下来就是接受实时数据库发送过来的采集信息进行界面实时动态刷新,包括用户通过客户端对设备进行的各种下发遥控等操作,发送到后台最终实现对硬件设备的控制,这个过程就是典型的实时监控系统的基本架构流程。我们今天只做好小小螺丝钉工作,提供一个可控制的刀闸开关控件。

具体实现之前先看看我们要达到的最终效果图片和视频

Screen Shot 2014-08-12 at 9.14.50 PM

 

记得十多年前我刚毕业的第一份工作就是负责电力SCADA的人机界面交互模块,当时大部分电力行业都是采用VC/MFC或QT来实现界面呈现,其实至今也依然如此,前端时间和老朋友聚会了解到他们还在用VC6编译系统,如今的VS20**根本跑不动他们庞大的古老系统,当然也许他们没配置好工具参数,但从一个侧面你可以感受到老系统迁移之重,大部分程序员处于为项目业务功能疲于奔命状态,上百号人这么多年在根本无力优化和重构的架子上不断堆积功能,我记得当时一个mousedown函数居然堆了六千多行代码,各种图元类型的draw代码也是长得不堪入目,这些老系统虽然不好维护但也考这么多程序员活生生的维护下来了,我们每天能正常的用水用电用气,背后都是靠着众多程序员的血汗维护着以如今眼光看完全不堪入目的烂代码,不得不承认在中国能用是第一位,其他问题只要堆人能解决的都不是问题。有点扯远了,上几张我以前电力实现的图库工具:

Screen Shot 2014-08-12 at 9.46.22 PM

实现功能并不难,当时也实现了组合和分解图元,能进行图库管理和用户自定义,我相信全世界肯定不下几百上千套绘图软件,刚开始我还是很兴奋,每天学习不同的绘制API,就能捣鼓出新效果,我也不在乎代码架构,每天就是以学习掌握更多的庞大MFC库为荣,但当你掌握大部分绘图技巧后,我发现自己每天维护这种庞大到无法以个人力量进行大规模重构,又不得不持续维护每天堆积功能性体力活代码时,我感觉自己在浪费生命,于是跳槽到了另外一家公司打算做电子商务,结果阴差阳错又被安排到电力部门干起来绘图工具,还好这次我能换个新语言Java,没有历史包袱完全自己重头设计图形架构,于是地球上出现了第1001个绘图工具:

Screen Shot 2014-08-12 at 10.35.33 PM

这一版设计上还是有很大的改进,图形绘制逻辑,交互代码以及界面布局等都进行了较合理的分工设计,那个Java和设计模式很火,人手一本Martin Fowler《Refactoring: Improving the Design of Existing Code》,犹如宗教信仰坚决执行一个函数不超过几十行的时代,一个mousedown几千行的代码已经绝迹了,但我还是很不满意,数据模型和界面绘制没有很好的有机结合机制,虽然电力要求界面有***的毫秒级响应,但大部分公司都是像游戏刷新机制那样不断repaint界面,是的,当时的数据模型没有任何事件派发机制,就是内存中的一堆数据,你无法知道哪个数据什么时候change了,因而只能不断的repaint界面,刷新周期太短对于大的网络拓扑图根本来不及更新,更新周期太长又达不到响应要求,至于所谓的***毫秒级响应我只能呵呵了,为了上这个系统一堆兄弟在沈阳某农村封闭了八个多月,我很好奇那个老系统现在是否健在…

回到我们的任务,一个刀闸最主要的就是可开闭的部分,其他部分都是装饰物效果而已,因此我采用HT的矢量来描述整个刀闸外观,其中需要开闭部分采用type为shape的一个线段来描述,并将其的rotation旋转参数通过func: ‘style@switch.angle’的描述来绑定到Node图元的switch.angle样式属性上

ht.Default.setImage('switch', {
    width: 100,
    height: 50,
    comps: [
        {
            type: 'roundRect',
            rect: [0, 0, 100, 50],
            background: '#2C3E50',
            gradient: 'linear.north'
        },
        {
            type: 'circle',
            rect: [10, 10, 10, 10],
            background: '#34495E',
            gradient: 'radial.center'
        },
        {
            type: 'circle',
            rect: [80, 10, 10, 10],
            background: '#34495E',
            gradient: 'radial.center'
        },
        {
            type: 'shape',
            points: [10, 40, 40, 40],
            borderWidth: 8,
            borderColor: '#40ACFF',
            border3d: true
        },
        {
            type: 'shape',
            points: [60, 40, 90, 40],
            borderWidth: 8,
            borderColor: '#40ACFF',
            border3d: true
        },
        {
            type: 'shape',
            points: [5, 40, 35, 40, 65, 40],
            segments: [1, 1, 2],
            borderWidth: 8,
            borderColor: '#40ACFF',
            border3d: true,
            borderCap: 'round',
            rotation: {
                value: -Math.PI/4,
                func: 'style@switch.angle'
            }
        },
        {
            type: 'circle',
            rect: [30, 35, 10, 10],
            borderColor: 'red',
            borderWidth: 5,
            border3d: true
        },
        {
            type: 'circle',
            rect: [60, 35, 10, 10],
            borderColor: 'red',
            borderWidth: 5,
            border3d: true
        }        
    ]
});

 

Screen Shot 2014-08-07 at 8.20.12 PM

以上是在矢量编辑器中打开的效果图,你可以清晰的看得到我们定义的几个元素的位置大小演示等,这样应用时只要构建一个Node对象,将其image设置为switch矢量,那么将来只需要调用node.setStyle(‘switch.angle’, Math.PI/6)就可以随时随地控制刀闸展开角度 。

这样封装还不够完美,对应用着来说他们只关心刀闸的打开和关闭的操作,他们并不关心旋转角度,开和关是业务角度的理解,而旋转角度是底层实现图形上的参数,并且用户还需要开关过程有动画效果,于是我们进行了进一步的封装,设计了ht.Switch的类,提供了setExpanded的函数,在函数里面操作底层绑定图形的‘switch.angle’属性,以及启动动画封装:

ht.Switch = function(){    
    ht.Switch.superClass.constructor.call(this); 
    this.s('switch.angle', 0);
};
ht.Default.def('ht.Switch', ht.Node, {
    _image : 'switch',
    _icon: 'switch',

    toggle: function (anim) {
        this.setExpanded(!this.isExpanded(), anim);
    },
    isExpanded: function () {
        return this.s('switch.angle') !== 0;
    },
    setExpanded: function (expanded, anim) {
        if(anim == null){
            anim = true;
        }
        var self = this,
            animation = self._animation,
            oldValue = self.isExpanded();

        if(animation){
            animation.stop(true);
            delete self._animation;
        }

        if (oldValue !== expanded) {                        
            var targetAngle = expanded ? -Math.PI/4 : 0;                      

            if(anim){                
                oldValue = self.s('switch.angle');                
                self._animation = ht.Default.startAnim({
                    action: function(t){
                        self.s('switch.angle', oldValue + (targetAngle-oldValue)*t);
                    }
                });                                                  
            }else{
                self.s('switch.angle', targetAngle);
            }            
        }
    }
});
 在我们的视频操作中你会发现通过属性页的拉条可以任意控制刀闸张角,同时通过isExpanded/setExpanded的boolean类型属性也可以勾选动画切换刀闸的开与关,细心的程序员你会发现不仅仅拓扑图上的刀闸动起来了,连TreeView上的刀闸对应的icon图标也是和矢量描述的效果一样,更惊喜的是树上的icon也是实时显示刀闸的展开角度,这是传统图片作为树的icon图片无法实现的,这也是我们一直强调的HT for Web整体架构已经为矢量打下基础,并非为了拓扑才实现矢量,所有通用组件都享有矢量的功能特性,这个后续我们会有更多的应用案例让大家体会到这种结合的强大之处,当然可维护性已经不用我多说了,传统的通用组件tree上自定义renderer也能实现一个能动的icon,但你可以想想工作量,我们没有写一行绘制代码,仅仅通过定义一个json的矢量就把GraphView和TreeView的事都干了,并且业务接口对上层应用人员来说就是一个node.setExpanded(true/false)之简单。
 

这里我只是随手搞了个非常ugly的刀闸,你可以让美工采用矢量绘图工具可视化的绘制更漂亮的效果,界面操作上你也可以通过graphView.mi监听交互事件,例如监听到双击刀闸时进行开关切换,甚至可以参考《透过WebGL 3D看动画Easing函数本质》的章节采用更洋相的Easing动画效果。

最后几点设计控件的建议:

  1. 切换到使用者角度,即站在上层应用者角度提供最简洁符合业务逻辑的API接口,尽量不暴露图形相关参数,图形参数对上层使用着是晦涩的,暴露了你自己也是非常难改动和维护
  2. 不要一开始设计就考虑如何操作,如何动画,操作和动画都可以在基础API基础上扩展再封装,某种程度上来说,如何操作和如何动画甚至不属于控件封装该干的,至少可再提供进一层的封装,这样可随意切换操作和动画逻辑,而不影响底层控件的数据模型和绘制逻辑
  3. 尽量让绘制代码和业务逻辑代码分离,这点如果采用最基础的绘制代码的确很难分离,这也是HT尽量采用矢量描述,不让用户控制底层绘制代码的初衷

Screen Shot 2014-08-12 at 8.57.11 PM

1
0
分享到:
评论

相关推荐

    ht6023&ht7038电源板原理图,ht6872电路图,PDF

    在电源板原理图中,这些组件会以图形形式呈现,连接线代表电路间的导通,方块表示集成电路,而其他图形则表示电阻、电容、电感等被动元件。通过阅读和理解原理图,工程师可以了解整个系统的运作方式,定位问题,进行...

    HT 手册-07311656.pdf

    HT-for-web 的概述、开发类库、开发工具、运行环境、函数简写、模型、设计模式、类包层次、工具类、数据类型、数据容器、选择模型、组件、配置、图片、动画、属性组件、列表组件、树形组件、表格组件、工具条组件、...

    ht_ht2002制图软件_java_

    【ht_ht2002制图软件】是一个专为用户设计的图形绘制工具,它采用Java编程语言开发,使得该软件具有跨平台性,可以在多种操作系统上运行,如Windows、Linux和Mac OS等。Java是一种面向对象的编程语言,以其“一次...

    ht-for-web

    【ht-for-web】是一款专为前端开发者设计的框架,主要用于创建和管理拓扑图以及页面布局。这个框架的强大之处在于它的灵活性和可定制性,使得开发者可以轻松地构建出复杂且交互性强的可视化应用。 在拓扑图制作方面...

    HT for Web 入门手册

    HT for Web是基于HTML5标准的企业应用图形界面一站式解决方案, 其包含通用组件、拓扑组件和3D渲染引擎等丰富的图形界面开发类库,提供了完全基于HTML5的矢量编辑器、拓扑编辑器及 3D场景编辑器等多套可视化设计工具...

    HT for Web Demo

    海马云是一家专注于2D/3D图形渲染及数据可视化的技术提供商,其开发的HT for Web库是一个强大的Web组件库,尤其适用于构建复杂的业务流程图、3D场景等。 在给定的资源中,我们可以看到以下几个关键文件: 1. **ht...

    hightopo HT for Web(hightopo.zip)

    【描述】:HighTopo(简称HT)是一款强大的Web图形库,它专为开发人员提供了构建现代化、跨桌面和移动终端的企业级应用的解决方案。通过使用HT for Web,开发者无需过于关注复杂的跨平台兼容性问题,以及在触屏设备...

    HT1621.rar

    标题中的"HT1621.rar"表明这是一个与HT1621相关的资源文件,通常在电子工程领域,HT1621是一款常见的...在实际应用中,开发人员可以利用这个驱动来控制HT1621显示各种文本、图形或者图标,从而实现设备的人机交互界面。

    合泰单片机应用能力设计大赛——HT-IDE3000操作步骤(HT66F70A).zip

    在电子工程领域,单片机是嵌入式系统的核心组件,广泛应用于各种设备的控制与数据处理。合泰单片机是其中一种常见的选择,尤其在教育和竞赛中颇受欢迎。"合泰单片机应用能力设计大赛"是为培养和提升参赛者对单片机的...

    LCD_HT1621模块资料

    1. **HT1621控制器**:HT1621是一款专用的液晶驱动控制器,由台湾辉达科技(Hitech)设计。它能够驱动多达8行×16列的点阵液晶显示器,同时支持128个字符的内部存储器,这使得它能够显示丰富的字符和简单的图形。 2...

    HT9B92 PDF

    根据所提供的信息,我们可以深入探讨有关HT9B92 LCD驱动IC的技术知识点。 HT9B92是一款专为液晶显示(LCD)设计...无论是开发者还是电子工程师,在设计用于多种应用场景的消费电子产品时,HT9B92都是值得考虑的组件。

    libht.js.zip

    其中,ht.js(又称libht.js)是一款专为数据可视化和图形交互设计的轻量级库,尤其在3D场景建模、科学计算可视化等方面表现出色。本文将详细介绍ht.js的核心功能、使用方法以及在实际项目中的应用场景。 ht.js的...

    stm8 驱动定制的段式液晶 HT1621

    HT1621是一种段式液晶显示控制器,专为驱动点阵或段式液晶屏设计。这种控制器可以管理多达128个独立的段,使得它适合于创建定制的字符或图形显示。它具有内置的RAM和译码功能,可以简化与微控制器的接口,减少外部...

    ht精华代码

    "vector"通常指的是矢量图,这类图像使用数学公式表示,可以在不同尺寸下保持清晰,常用于图形设计和网页艺术。"master"可能是Git仓库的主分支,表明这是项目的核心部分,包含了完整的源代码和资源文件。 在这个...

    基于HT for Web矢量实现HTML5文件上传进度条

    HT for Web是一款强大的Web可视化工具,它允许开发者通过矢量图形来构建交互式的Web应用程序。在HTML5中,File API提供了处理文件和数据的能力,包括读取本地文件、监控文件上传进度等功能。 这篇博客(博文链接:...

    基于HT for Web矢量实现HTML5上传文件进度条

    HT for Web支持矢量图形,这意味着它可以绘制出清晰、高分辨率的图形,无论屏幕分辨率如何,都能保持良好的显示效果。 在HTML5中,`<input type="file">`元素提供了一个简单的文件选择对话框,允许用户选择一个或多...

    HT1621B的英文资料

    HT1621B 是一款 128 图形(32×4)的 RAM 映射多功能 LCD 驱动器。其软件配置特性使其适用于多种 LCD 应用场景,包括 LCD 模块和显示子系统。仅需三条或四条线即可完成与主机控制器之间的接口。此外,HT1621B 包含...

    HT66F40 LCD+LED+KEY

    在这个例程中,合泰(Holtek)的HT66F40单片机被用于控制LCD显示屏、LED灯以及按键,这些都是嵌入式系统中常见的硬件组件。 **HT66F40微控制器** HT66F40是一款8位的微控制器,属于Holtek的HT6x系列。它集成了中央...

    液晶模块HT028MQV003NH-18PIN_9341资料包

    液晶模块HT028MQV003NH-18PIN_9341是一款广泛应用在电子设备中的显示组件,其技术细节和使用方法是理解该资料包的关键内容。本资料包提供了关于这款液晶模块的详尽信息,帮助开发者、工程师和爱好者更好地理解和使用...

Global site tag (gtag.js) - Google Analytics