中科院的某个客户遇到这样的需求:将区域内所有水文观测站信息按层次结构展现出来。原来用的是mxGraph组件,遇到几个问题:布局难以定制、节点样式难定制、交互有问题,后来改用Qunee组件,顺利解决问题。
这是一种典型应用,主要用到Qunee的布局类TreeLayouter,以及UI和交互的简单定制,下面以示例来做介绍
按水文观测站区域与级别分五个等级,最顶层的是主站点,下面分区站点,再往下子站点,最后是实际观测点或者设备,因为站点总数量几千上万,为了便于查看,采用动态加载方式,点击站点节点的加号,动态加载子站点,并执行自动布局
最终的效果类似下面截图
这里将Graph组件直接嵌入到document.body,并设置body尺寸布满整个窗口
var graph, canvas, root, layouter; function init() { canvas = document.body; function updateGraphSize() { canvas.style.width = window.innerWidth + "px"; canvas.style.height = window.innerHeight + "px"; if (graph) { graph.moveToCenter(); } } window.onresize = updateGraphSize; updateGraphSize(); graph = new Q.Graph(canvas); } Q.addEventListener(window, "load", init);
树形布局
考虑到子站点数据较多,利用屏幕宽度大于高度的特点,选择从左向右分布
function init() { ... layouter = new Q.TreeLayouter(graph); layouter.parentChildrenDirection = Q.Consts.DIRECTION_RIGHT; layouter.hGap = 50; layouter.vGap = 40; }
因为第二层节点的孩子数量较多,所以采用两侧布局,其后的节点方向也保持从左向右
if (level == 1) {//设置第二层孩子布局方式 node.layoutType = Q.Consts.LAYOUT_TYPE_TWO_SIDE; } else if (level == 2) {//设置第三层布局方向与连线类型 node.parentChildrenDirection = Q.Consts.DIRECTION_RIGHT; edge.edgeType = Q.Consts.EDGE_TYPE_HORIZONTAL_VERTICAL; }
根据应用需要,通过Q.Node#addUI(…)方法,对节点添加不同的图标,放置在不同位置,并关联相关属性
function createGraphNode(name, icon, canAdd, showDetail) { var node = graph.createNode(name); node.setStyle(Q.Styles.BACKGROUND_COLOR, Q.toColor(0xEEDDDDDD)); node.setStyle(Q.Styles.PADDING, new Q.Insets(2, 5)); node.setStyle(Q.Styles.BACKGROUND_GRADIENT, backgroundGradient); node.setStyle(Q.Styles.BORDER, 1); node.setStyle(Q.Styles.BORDER_COLOR, Q.toColor(0x555555)); if (icon) { node.image = icon; node.setStyle(Q.Styles.LABEL_POSITION, Q.Position.RIGHT_MIDDLE); node.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.LEFT_MIDDLE); return node; } node.image = "./empty.png"; node.setStyle(Q.Styles.LABEL_POSITION, Q.Position.CENTER_TOP); node.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.CENTER_BOTTOM); if (canAdd) { var ui = new Q.ImageUI("./add.png"); ui.name = "add"; ui.position = Q.Position.CENTER_BOTTOM; if (showDetail) { ui.anchorPosition = Q.Position.LEFT_TOP; ui.offsetX = 10; } else { ui.anchorPosition = Q.Position.CENTER_TOP; } ui.showPointer = false; node.addUI(ui, { property: "icon1", propertyType: Q.Consts.PROPERTY_TYPE_CLIENT, bindingProperty: "data" }); node.set("icon1", "./add.png"); } if (showDetail) { var ui = new Q.ImageUI("./detail.png"); ui.name = "showDetail"; ui.position = Q.Position.CENTER_BOTTOM; ui.anchorPosition = Q.Position.CENTER_TOP; if (canAdd) { ui.anchorPosition = Q.Position.RIGHT_TOP; ui.offsetX = -10; } else { ui.anchorPosition = Q.Position.CENTER_TOP; } ui.showPointer = false; node.addUI(ui); } return node; }
创建连线,并指定连线类型为正交类型
function createGraphEdge(from, to) { var edge = graph.createEdge(from, to); edge.edgeType = Q.Consts.EDGE_TYPE_ORTHOGONAL_HORIZONTAL; edge.setStyle(Q.Styles.EDGE_SPLIT_BY_PERCENT, false); edge.setStyle(Q.Styles.EDGE_SPLIT_VALUE, 15); return edge; }
根据点击位置,执行不同动作
graph.onclick = function (evt) { var target = graph.hitTest(evt); if (!target || target instanceof Q.ElementUI) { return; } if (target.name == "add") { var ui = target.parent; if (ui && ui.data instanceof Q.Node && !ui.data.userData.isEnd) { loadChildren(onDataLoad, ui.data); } } else if (target.name == "showDetail") { var ui = target.parent; if (ui && ui.data instanceof Q.Node) { alert(ui.data.userData.fld_name); } } } graph.ondblclick = function (evt) { var ui = graph.getUIByMouseEvent(evt); if (!ui || !(ui.data instanceof Q.Node)) { layouter.doLayout(); graph.zoomToOverview(); return; } var node = ui.data; if (node.userData.isEnd) { return; } loadChildren(onDataLoad, node); }
http://demo.qunee.com/waterwsn/
如需代码请与support@qunee.com联系