工作流设计器之跟踪器


第 8 章 跟踪器

event -> tracker -> findByXXX -> request -> command。

8.1. 次序图

0108-01.png

次序图

图 8.1. 次序图


当用户执行“拖拽”,“点击”,“按键”时,就会根据当前情况自动绑定对应的tracker。

tracker会在操作执行完成后生成对应的request,request发送给相应的editPart。

editPart将request组装成command,command统一发送给CommandStack。

command执行时会改变model中的属性,model的属性改变时会生成提醒消息。

model的提醒消息会发送给注册在model上的editpart,由editpart负责更新figure。

至此整个操作结束。

提示

目前,所有的Command都是通过EditPart创建的,但是,似乎Command和EditPart没有必然的创建与被创建的关系,是否应该把所有的Command创建工作都放到其他地方,让命令直接作用于Model。

8.2. 跟踪器分类


表 8.1. 跟踪器分类

名称说明
CreateNodeRequestTracker从palette中向画布中拖拽添加节点。
CreateEdgeRequestTracker拖动创建节点间的连线。
MarqueeRequestTracker框选多个节点。
MoveNodeRequestTracker移动节点的位置。
MoveEdgeRequestTracker修改连线的起始节点。
MoveTextRequestTracker修改连线名称的位置。
ResizeNodeRequestTracker修改节点的大小。
ResizeEdgeRequestTracker拖动修改折线的形状。
DirectEditRequestTracker双击修改节点或连线的名称。
RemoveRequestTracker删除节点或连线。
SelectionRequestTracker选中节点或连线,包括多选。
SelectionListenerRequestListener选中元素改变时进行提醒。
ToolTracker判断选中浮动工具。


8.3. 跟踪器执行顺序

我们从原本的每次鼠标事件都进行遍历,确定哪些tracker可以起作用,修改为现在的每次MOUSE_DOWN时进行遍历,选中对应的tracker,并将该tracker绑定在browserListener中,这样后续的MOUSE_MOVE和MOUSE_UP都不会进行额外的遍历,直接使用绑定的tracker进行处理。减少了不必要的性能消耗,避免了多个tracker同时处理事件造成的不确定性。


表 8.2. 跟踪器分类

名称说明
SelectionRequestTracker选中节点或连线,包括多选。
DirectEditRequestTracker双击修改节点或连线的名称。
ToolTracker判断选中浮动工具。
CreateNodeRequestTracker从palette中向画布中拖拽添加节点。
CreateEdgeRequestTracker拖动创建节点间的连线。
ResizeNodeRequestTracker修改节点的大小。
ResizeEdgeRequestTracker拖动修改折线的形状。
MoveEdgeRequestTracker修改连线的起始节点。
MoveNodeRequestTracker移动节点的位置。
MoveTextRequestTracker修改连线名称的位置。
MarqueeRequestTracker框选多个节点。
RemoveRequestTracker删除节点或连线。
SelectionListenerRequestListener选中元素改变时进行提醒。


8.4. SelectionRequestTracker

现在已经将SelectionRequestTracker单独从tracker队列中抽离出来,放在所有tracker执行之前,用以判断用户当前选中的节点或连线。

如果当前没有选中节点,鼠标点击的节点就会被选中

连线没有多选情况,每次只能选中一条连线。

如果当前选中了多个节点,并且鼠标目前点击的节点已经选中了,就不做变化。

如果当前选中了多个节点,鼠标点击了一个未选中的节点,那么就选中这个节点,同时取消其他节点的选择。

如果按住ctrl,再选择节点,已经选中的节点不会变化。如果鼠标点击了一个未选中的节点,就选中这个节点,如果鼠标点击一个已经选中的节点,就取消这个节点的选择。

8.5. SelectionListenerTracker

现在已将SelectionListenerTracker单独从tracker队列中抽离出来,放在所有tracker执行之后,用以判断当前选中节点或连线是否发生了改变。

8.6. DirectEditRequestTracker

鼠标双击文字时,显示输入框等待用户修改。

鼠标事件为双击时,事件目标为text或textbox时启用tracker。

启动tracker的同时,显示TextEditor。

启用tracker过程中。

如果点击了ENTER键,则完成修改。

如果点击了ESC键,则取消修改

如果鼠标单击了INPUT(TextEditor)以外的部分,则完成修改。

8.7. CreateNodeRequestTracker

鼠标单击工具栏,事件目标为可用的palette时启用tracker。

启用同时初始化DraggingRect。

启动过程中。

鼠标移动则DraggingRect随同移动。

放开鼠标左键,则根据最初选择的palette创建节点,并放入画板中。

8.8. CreateEdgeRequestTracker

首先工具条上,当前选中的palette必须是connection才行。

然后在鼠标单击一个节点时启动tracker。

启动的同时会初始化draggingEdge。

启动过程中。

鼠标移动时,会根据最初选择的palette更新draggingEdge的位置。

放开鼠标左键,会判断鼠标当前是否放在节点上,如果是,就创建最初选择节点和当前节点之间的连线,如果不是,就隐藏draggingEdge。

8.9. MarqueeRequestTracker

鼠标单击画板空白(在画板中,但是点击处既没有节点,也没有连线)则启动tracker。

启动的同时会初始化draggingNode

启动过程中。

鼠标移动,就根据开始点击的位置和当前鼠标的位置更新draggingRect

放开鼠标左键,会根据当前draggingRect的面积计算哪些节点被选中了。

MarqueeRequestListener同时也实现了点击空白取消所有已选中节点的功能。

8.10. MoveNodeRequestTracker

鼠标点击一个节点的同时,就启用tracker。

启用的同时判断当前是否为多选模式,如果不是多选模式,就清空之前选中的节点连线,然后选中当前点击的节点。同时创建draggingRect。

启动过程中

鼠标移动,draggingRect跟着移动。

放开鼠标左键,会根据当前鼠标位置移动最开始的时候选中的节点。

MoveNodeRequestTracker支持同时拖拽多个节点。

8.11. MoveEdgeRequestTracker

鼠标点击edgeHandler的start或者end部分,才能启用tracker

启用的同时会创建draggingEdge

启动过程中

鼠标移动,draggingEdge会对应移动

放开鼠标左键,如果鼠标处于一个节点上方,就把连线的对应端连接到节点上。

8.12. MoveTextRequestTracker

鼠标点击edge的text就会启动tracker。

启动同时会清空之前已经选择的所有节点和连线。

启动过程中

鼠标移动,text和texthandler会对应移动

放开鼠标左键,会发送textMove命令。

8.13. RemoveRequestTracker

点击DEL键删除当前选中的节点或连线。

点击CTRL+A选中所有节点。

8.14. ResizeNodeRequestTracker

点击nodeHandler的八个方向的handle就可以启动tracker

启动同时会初始化draggingRect

启动过程中

鼠标移动,draggingRect会对应移动

放开鼠标左键,node和nodeHandle随之移动。

8.15. ResizeEdgeRequestTracker

点击edgeHandler的中间点可以启动tracker

启动的同时不会创建draggingEdge

启动过程中

鼠标移动,连线和edgeHandler会随之修改

放开鼠标,就停止修改。

8.16. ToolTracker

点击nodeHandler四周的tool就会启动tracker

启动后,toolTracker会把drag, move, drop事件分发给对应的tool

8.17. 变更

考虑把MoveTextRequestTracker放在监听器的最前面,为了可以在父子节点覆盖的时候,可以选中子连线上的文字。

总体的变更思想是把更细小的,更不容易选中的放在前面,更巨大的,更容易选中的放在后边,以此理论对tracker的顺序进行重排。

还要考虑如果在需要覆盖tracker队列中的某个tracker,该如何操作,目前的实现方式几乎无法覆盖单独的tracker,只能重写BrowserListener。

提示

还有一点隐形的问题,我们需要统一findEditPart()方法的实现方式,目前分为两种,一种方式与gef的理论一样,根据鼠标当前坐标遍历计算获得选中了哪个EditPart。但是有些时候偷懒直接通过VML和SVG的特性根据event.target直接获得了当前点击的dom对象,然后通过dom对象的id获得了对应的EditPart。

下一步的目标将所有的选中方式都切换成第一种方式。这样有两个好处,第一可以增强gef的通用性,因为canvas之类非xml形式的绘图方式,是没有target可供我们使用的。第二可以解决线太细不好选择的问题。

但是怕多次遍历性能会出现损耗。另外还是线的问题,目前可以在dom上设置cursor让鼠标浮动到线上面的时候显示pointer形式的鼠标进行标示。如果采用了第一种选择方式,还不清楚如何在鼠标没浮动到连线dom上面就改变鼠标的样式。如果不容易修改,我们就只能暂时不改变鼠标的样式了。


上一篇 下一篇

评论



分享