HT for Webhttp://www.hightopo.com/guide/readme.html)提供了涵盖通用组件、2D拓扑图形组件以及3D引擎的一站式解决方案,正如Hightopo官网所表达的我们希望提供:Everything you need to create cutting-edge 2D and 3D visualization. 这个愿景从功能上是个相当长的战线,从设计架构上也是极具挑战性的,其实HT团队是非常保守的,我们从不贪多图大,只做我们感觉自己能得更好,能给用户综合体验更佳的功能,在这样理念驱动下我们慢慢形成了这样的愿景,慢慢实现了几个有意义的里程碑,慢慢积累下了不少图形组件设计上的创新和经验,我不知道这个系列会写多少篇,也许永远也不会结束,也没有系统的提纲规划,想到什么就写什么,只希望文章能启发有兴趣的同学对图形组件设计更深的思考就足够了。

讨论前先设定话题的边界,HT是基于HTML5的图形组件库,因此文章的案例更多会涉及HTML和JavaScript语言,但并不局限于Web前端,设计思想上同样适用于任何GUI语言平台。完整的前端设计是需要考虑到后台加载并发等因素,但本系列更侧重于纯客户端图形组件,不涉及网络通讯部分的思考,例如最近阿里无线前端招聘让谈谈:讲讲输入完网址按下回车,到看到网页这个过程中发生了什么。这是个能讨论出很多方方面面,让你了解面试者的好话题,但这里讨论的话题会与以下关键字更为相关:企业应用、Single Page Application、重客户端交互、监控、MV*等。

如Linus大神所言:Talk is cheap, show me the code.  因此我选择在话题展开之前,先用HT来扩展定制几个应用案例,以便大家了解HT组件及其扩展设计思路。

http://www.hightopo.com/guide/guide/core/propertyview/examples/example_custom.html

熟悉Flex的程序员应该都了解Tour de Flex这个包罗万象的大杂烩,其中的网络监控拓扑Network Monitor特别其动画切换效果一直给我很深印象,这里不可能有篇幅实现完整例子,我们仅尝试实现其展示CPU和MEM的界面部分。

实现的最终效果如上图所示,模型数据就两个数值,一个代表CPU占用率,一个代表内存占用率,左侧通过HT的图形组件GraphView自定义了矢量图形展示,右上角自定义了属性页PropertyView的两单元格的Renderer,右下角两个Slider可拖动改变CPU和MEN值。

此例子麻雀虽小五脏俱全,三个部分分别采用三种方式实现了自定义组件,同时不同组件共享同一数据源,在呈现的基础上还支持桌面和移动端的Mouse和Touch的交互,还有不同终端屏幕的组件布局功能。

业务上需要在占用率小于40%时呈现律师,40%-70%时显示黄色,超过70%时呈现红色,因此定义了如下getColor的工具函数:

	getColor = function(value) {
if (value < 40)
return '#00A406';
if (value < 70)
return '#FFCC00';
return '#A60000';
};

PropertyView上采用的最基础和原始的方式,通过Canvas画笔进行单元格的自定义绘制,在注册PropertyView时重载drawPropertyValue函数即可实现单元格自定义Renderer的绘制

drawFunc = function(g, value, x, y, w, h){
g.fillStyle = '#A1A1A3';
g.beginPath();
g.rect(x, y, w, h);
g.fill();
g.fillStyle = getColor(value);
g.beginPath();
g.rect(x, y, w * value / 100, h);
g.fill();
ht.Default.drawText(g, value + '%', '12px Arial', 'white', x, y, w, h, 'center');
};
propertyView.addProperties([
{
displayName: 'CPU',
drawPropertyValue: function(g, property, value, rowIndex, x, y, w, h, data, view) {
drawFunc(g, data.a('cpu'), x, y, w, h);
}
},
{
displayName: 'MEM',
drawPropertyValue: function(g, property, value, rowIndex, x, y, w, h, data, view) {
drawFunc(g, data.a('mem'), x, y, w, h);
}
}
]);

Slider拉条部分直接在HT封装的组件之上应用,因而无需接触到最底层的Canvas画笔绘制,仅需要在onValueChanged时更新leftBackgroud拉条左侧颜色即可,其实也可以通过重载Slider的getLeftBackground函数实现:

formPane.addRow(['CPU', {
slider: {
step: 1,
onValueChanged: function(){
var value = this.getValue();
node.a('cpu', value);
this.setLeftBackground(getColor(value));
},
value: node.a('cpu')
}
}], [50, 0.1]);
formPane.addRow(['MEM', {
slider: {
step: 1,
onValueChanged: function(){
var value = this.getValue();
node.a('mem', value);
this.setLeftBackground(getColor(value));
},
value: node.a('mem')
}
}], [50, 0.1]);

GraphView部分采用了《HT全矢量化的图形组件设计》文章介绍的HT自定义的矢量方式来实现图形效果,这种方式介于以上两种扩展方式之间,需要自定义绘制效果,但通过HT提供的矢量格式,用户可采用较为直观易读的JSON格式来描述图形,并通过数据绑定的方式实现模型数据与界面呈现的关联,避免如第一种自定义renderer的方式,即需要接触到底层绘制函数,同时业务逻辑代码与绘制代码混杂一起不易维护的问题。

ht.Default.setImage('server_image', {
width: 300,
height: 200,
comps: [
{
type: "roundRect",
rect: [3, 5, 291, 189],
background: "#E3E3E3",
gradient: "linear.northeast",
shadow: true
},
{
type: "text",
text: "CPU",
font: "16px Arial",
rect: [20, 45, 59, 41]
},
{
type: "text",
text: "MEM",
font: "16px Arial",
rect: [20, 108, 59, 41]
},
{
type: "rect",
rect: [82, 55, 145, 22],
background: "#A1A1A3"
},
{
type: "rect",
rect: {
func: function(data) {
return [82, 55, 145 * data.a('cpu') / 100, 22];
}
},
background: {
func: function(data) {
return getColor(data.a('cpu'));
}
}
},
{
type: "rect",
rect: [82, 117, 145, 22],
background: "#A1A1A3"
},
{
type: "rect",
rect: {
func: function(data) {
return [82, 117, 145 * data.a('mem') / 100, 22];
}
},
background: {
func: function(data) {
return getColor(data.a('mem'));
}
}
},
{
type: "text",
font: "16px Arial",
rect: [240, 49, 53, 31],
text: {
func: function(data) {
return data.a('cpu') + '%';
}
},
color: {
func: function(data) {
return getColor(data.a('cpu'));
}
}
},
{
type: "text",
font: "16px Arial",
rect: [240, 108, 47, 39],
text: {
func: function(data) {
return data.a('mem') + '%';
}
},
color: {
func: function(data) {
return getColor(data.a('mem'));
}
}
}
]
});

以上代码注册了名为server-image的图片,绑定了attr上的mem和cpu的两个属性,因此做完这些手脚架的基础工作后,应用人员只需要构建ht.Node对象,通过node.setImage('server-image')即可实现该图元在GraphView上呈现'server-image'描述的矢量效果,并且PropertyView、Slider和GraphView三个组件都通过node的attr上的cpu和mem来显示界面,这样当后台获取到采集的实时数据后,只需要更新到node的attr上的cpu和mem属性,则界面上的所有组件就会自定更新显示:

node = new ht.Node();
node.setName('SERVER');
node.setImage('server_image');
node.a({
cpu: 30,
mem: 70
});
dataModel.add(node);

当然实际应用中并不需要拉条改变CPU和MEN值,这些值一般通过后台采集实时自动更新仅作为呈现,但有了前端这些组件的一站式支持,我们不需要连接后台也可以很方便在客户端进行模拟测试,有了这样的机制我们就可以分离模块一步步测试,例如我们现在不需要连接服务器也可以测试矢量描述定义的是否正确,数值改变后绿黄红的业务颜色更新是否正确,各个组件的数据同步是否正常,Mouse和Touch交互是否能正常操作,界面在不同设备屏幕上显示是否正常等等,这些纯客户端组件的封装工作都做到位后,你就可以安心连接后台数据进行测试了。

见过太多客户出问题时只会说:界面显示不对。这样的问题描述完全无法定位根源,到底时后台数据库问题,网络通讯问题,解析数据问题,设置模型问题还是组件封装问题?这也是MVC/MVP/MVVM存在的另外一个层面的意义,MV*除了事件派发数据绑定外,能更好的进行呈现、模型和业务逻辑的分工切割进行独立测试的重要意义,就行TCP/IP七层协议的分类,每个协议层都应该确保正确实现自己的协定约定,并且每一层可进行独立的测试,这才是可维护可扩展的系统,因此对于HT客户遇到问题时,我们一般也是一层层的帮忙梳理找根源,如果矢量描述没问题呈现出错,那是HT组件库的问题,如果模拟到Node上的attr数据显示正确,那就去找找实际运行后台通信解析后的数据是否正确的设置到模型上,这样一步步的分析很容易就能定位到问题的根源。

以上三种扩展方式各有利弊,我将在下篇中继续展开分析,本篇结尾上一段该例子在移动终端的运行操作视频

HTML5拓扑图形组件设计之道(一)的更多相关文章

  1. 矢量化的HTML5拓扑图形组件设计

    HT一直被客户称道的就是其全矢量化的设计特色,矢量相比传统图片好处太多了: www.hightopo.com/guide/guide/core/vector/ht-vector-guide.html ...

  2. HT图形组件设计之道(四)

    在<HT图形组件设计之道(二)>我们展示了HT在2D图形矢量的数据绑定功能,这种机制不仅可用于2D图形,HT的通用组件甚至3D引擎都具备这种数据绑定机制,此篇我们将构建一个3D飞机模型,展 ...

  3. HT图形组件设计之道(一)

    HT for Web简称HT提供了涵盖通用组件.2D拓扑图形组件以及3D引擎的一站式解决方案,正如Hightopo官网所表达的我们希望提供:Everything you need to create ...

  4. HT图形组件设计之道(三)

    上篇我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动,这类案例后续文章还会继续以便大家掌握更多的矢量应用场景,本篇我们先切换个话题, ...

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

    上一篇我们自定义CPU和内存的展示界面效果,这篇我们将继续采用HT完成一个新任务:实现一个能进行展开和合并切换动作的刀闸控件.对于电力SCADA和工业控制等领域的人机交互界面常需要预定义一堆的行业标准 ...

  6. HT全矢量化的图形组件设计

    HT一直被客户称道的就是其全矢量化的设计特色,矢量相比传统图片好处太多了: 矢量可无级缩放,界面不失真不模糊 描述矢量的文本内容远比图片小得多 目前各种window.devicePixelRatio不 ...

  7. 数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇

    HT 是啥:Everything you need to create cutting-edge 2D and 3D visualization. 这口号是当年心目中的产品方向,接着就朝这个方向慢慢打 ...

  8. HTML5 例子学习 HT 图形组件

    HTML5 例子学习 HT 图形组件 HT 是啥:Everything you need to create cutting-edge 2D and 3D visualization. 这口号是当年心 ...

  9. 数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇

    <数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇>一文让读者了解了 HT的 2D 拓扑图组件使用,本文将对 HT 的 3D 功能做个综合性的介绍,以便初学者可快速上手使用 HT ...

随机推荐

  1. Service简介

    Service是在一段不定的时间运行在后台,不和用户交互应用组件.每个Service必须在manifest中 通过<service>来声明.可以通过contect.startservice ...

  2. android知识杂记(三)

    记录项目中的android零碎知识点,用以备忘. 1.android 自定义权限 app可以自定义属于自己的权限: <permission android:description="s ...

  3. Sensor(ACCELEROMETER)

    package com.example.sensor01; import java.util.List; import android.hardware.Sensor; import android. ...

  4. UWP滑动后退

    经过近些年智能手机App的不断发展,用户已经不仅仅满足于功能上的需求.UI.设计等非功能点逐渐在App体验中占了大多数的分数.不知从何时起,滑动手势就成为了App的一个标配.他不仅仅是一个功能,更是一 ...

  5. Boyer-Moore 字符串匹配算法

    字符串匹配问题的形式定义: 文本(Text)是一个长度为 n 的数组 T[1..n]: 模式(Pattern)是一个长度为 m 且 m≤n 的数组 P[1..m]: T 和 P 中的元素都属于有限的字 ...

  6. WCF基础教程之异常处理:你的Try..Catch语句真的能捕获到异常吗?

    在上一篇WCF基础教程之开篇:创建.测试和调用WCF博客中,我们简单的介绍了如何创建一个WCF服务并调用这个服务.其实,上一篇博客主要是为了今天这篇博客做铺垫,考虑到网上大多数WCF教程都是从基础讲起 ...

  7. 关于JavaScript内存泄漏的质疑

    近几天看了些关于JavaScript内存管理的文章,相对于Java JVM的内存管理,显得简单些. 在学习的过程中,发现有不少网友谈到了循环引用,说循环引用会造成内存泄漏,垃圾回收器无法回收. 实际上 ...

  8. 可伸缩性最佳实践:来自eBay的经验

    看到一篇关于系统可伸缩性(可扩展)的文章,eBay的架构师Randy Shoup写的,原文出处没找到,就不写转载的地址了.根据自己的理解对文章有修改剪切的地方. 在eBay,可伸缩性是我们每天奋力抵抗 ...

  9. 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常

    回到目录 问题描述: SqlDateTime 溢出.必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间 概念相关 .Net中的DateTime结 ...

  10. 在ubuntu上安装nodejs[开启实时web时代]

    作为一名菜鸟,竟然在centos桌面上连输入命令行的地方都找不到,是在是对不起开山祖师,最后苍天不负苦心人,在ubuntu上找见了 [安装过程参考了http://cnodejs.org/topic/4 ...