HTML5 Canvas 数据持久化存储之属性列表
正常我们设置属性的时候,属性和属性值的 key value 对应,但是在实际开发中,经常遇到属性值可能需要从多项中选择,这个时候用原生的 HTML5 配合 JavaScript 来实现这个功能会让人非常头疼,我试着用 HT for Web 来实现了这个功能,感觉整体实践起来还是比较容易的,所以在这边跟大家分享一下。
本例链接: http://www.hightopo.com/demo/propertyEditor/index.html
本例效果图:
从上面的效果图中我们可以看到,整个页面分为三个部分,左边的 graphView 拓扑图部分,右下角的 tablePane 表格部分,以及右上角的 propertyView 属性部分。我们先把整个场景划分出来,然后再向各个部分来添加具体的内容:
gv = new ht.graph.GraphView();
var tablePane = new ht.widget.TablePane(gv.dm());//表格面板组件
propertyView = new ht.widget.PropertyView(gv.dm());//formPane是在propertyView里的,所以要先定义
var rightView = new ht.widget.SplitView(propertyView, tablePane, 'v', 0.4);//分割组件,v分为上下层,比例为0.4:0.6
rightView.getView().style.borderLeft = '1px solid #000';
var borderPane = new ht.widget.BorderPane();//边框面板组件
borderPane.setRightView(rightView, 400);//设置 borderPane 右边组件为 rightView,宽度为400
borderPane.setCenterView(gv);//设置 borderPane 中间组件为 gv
borderPane.addToDOM();//将 borderPane 组件添加进 body 中
createTable 函数我们后面再讨论。上面代码中 new 出来的部分都是 HT 封装好的组件,相当于“类”,这里解释一下 SplitView 分割组件,分割组件用于左右或上下分割两个子组件, 子组件可为 HT 框架提供的组件,也可为 HTML 的原生组件,子组件以 position 为 absolute 方式进行绝对定位,这个组件中的参数分别为(左组件或上组件, 右组件或下组件,h 表示左右分割 v 表示上下分割,分割位置默认值为 0.5,如果设置值为 0~1 则按百分比分割,大于 1 代表左组件或上组件的绝对宽或高,小于 1 代表右组件或下组件的绝对宽或高)。这里我们用了两次 SplitView,目的是将场景分成三个部分。最后记得一定要将组件添加进 body 中或者任意一个 HTML 标签中,这样才能在界面上显示,其中 addToDOM 的定义内容如下:
addToDOM = function(){
var self = this,
view = self.getView(), //获取这个组件的底层 div
style = view.style;//获取底层 div 的样式 style 属性
document.body.appendChild(view); //将底层 div 添加进 body 中
style.left = '0';//HT 默认将组件都定义为决定定位 absolute,所以需要设置位置
style.right = '0';
style.top = '0';
style.bottom = '0';
window.addEventListener('resize', function () { self.iv(); }, false);
}
HT 的组件一般都会嵌入 BorderPane、SplitView 和 TabView 等容器中使用,而最外层的 HT 组件则需要用户手工将 getView() 返回的底层 div 元素添加到页面的 DOM 元素中,这里需要注意的是,当父容器大小变化时,如果父容器是 BorderPane 和 SplitView 等这些 HT 预定义的容器组件,则 HT 的容器会自动递归调用孩子组件 invalidate 函数通知更新。但如果父容器是原生的 html 元素, 则 HT 组件无法获知需要更新,因此最外层的 HT 组件一般需要监听 window 的窗口大小变化事件,调用最外层组件 invalidate 函数进行更新。
场景创建完毕。为了显示不同节点对应的属性的不同,我们在拓扑图上添加了七个节点:
function initModel(){
var name = "设备";
var count = 0;
var root = createNode(name + count++, name + (++count));//参数1为name,参数2为tag
root.setImage('./symbols/机房/服务器.json');
root.setName('服务器');
root.s('label.position', 3);
gv.sm().ss(root);//默认选中root节点
for (var i = 0; i < 2; i++) {
var iNode = createNode(name + count++, name + (++count));//参数1为name,参数2为tag
createEdge(root, iNode);
for (var j = 0; j < 2; j++) {
var jNode = createNode(name + count++, name + (++count));
createEdge(iNode, jNode);
}
}
}
createNode 函数的声明如下:
function createNode(name, tag){//创建Node节点
flag++;
var node = new ht.Node();
node.setName(name);
node.setTag(tag);
node.setImage('./symbols/机房/XX分系统.json');
node.a('hidden', false);//自定义属性,可以控制node.a('hidden')来控制节点显隐
node.a('接口类型', 'SATA');
node.a('显卡', 'Nvidia');
if(flag % 2 === 0){
node.a('接口类型', 'IDE');
node.a('显卡', 'ATI');
}
node.s('label.position', 11);
gv.dm().add(node);//将节点添加进数据容器DataModel中
node.tablePane1 = createTableView(serviceType, dataModel1);//创建表格面板
node.tablePane2 = createTableView(serviceSize, dataModel2);
node.tablePane3 = createTableView(version, dataModel3);
node.formPane1 = createFormPane(node.tablePane1);//创建表单面板
node.formPane1.title = '类型';//为了给后面dialog对话框的标题做准备
node.formPane2 = createFormPane(node.tablePane2);
node.formPane2.title = '内存';
node.formPane3 = createFormPane(node.tablePane3);
node.formPane3.title = '型号';
if(flag % 3 === 0){
node.formPane3.v('tag', '联想(Lenovo)服务器X3650M5 8871');
}else{
node.formPane3.v('tag', 'Lenovo IBM X3250 5458I21');
}
node.a