== RFC 002: Connectors == This RFC contains a proposal on how to add support for more flexible connectors and better support for editing Molecular Interaction Maps. == Object anchors == All lines will be potential connectors and snap to an object if close enough. A line end can snap to an anchor point on the object, e.g. the centers of the four sides: ----o---- | | o o | | ----o---- The object's anchor points will not be stored in GPML. In the code, the view part of the object provides the possible anchor points to the line. We can extend this later to support custom anchors, set by the user. * AP: I think this is clearly a good idea. When drawing (or cleaning up) pathways, currently, I usually try to place lines at the centers of the four sides anyways. It is important to ''not'' explicitly store the anchors, of course, so that the GPML is more generalizable. == Line anchors == To properly represent mediators of interactions/reactions, we need to be able to connect a connector to another connector, e.g.: Enzyme | | v Substrate -----o-----> Product (0.5) Here we introduce a line anchor, which is similar to the object anchor, except that this anchor is stored in GPML. We need to store this, because the anchor will be explicitely created by the user as a specific point on the line. The line anchor's coordinates are 1-dimensional and range from 0 (start) to 1 (end). * AP: Would the 1-D anchor coordinate work with all elbow and curved lines types? * TK: Yes, if the coordinate would be 0.4, the connector will be placed at 40% of the total lentgh of the path. The exact position will differ if you change from straight to elbow connector, however. == Elbow connectors == To improve the layout of pathways we will support elbow connectors. The first or last segment always comes in or out of the object either in the x or y direction. By following this rule, there can be 0, 1 or 2 middle segments: Gene1 ------------- | | v Gene 2 Gene1 ------ | + | ---->Gene 2 Gene1 ------------------- | + | Gene2 <-- Gene1 ---- | | + Gene2 | | |----+---- The position of these middle segments (marked with +) can be changed by the user. We can store this information using the coordinates of the + points (waypoints). Often, a given connector can be rendered in two ways: Gene1 ------------- | | v Gene 2 Gene1 | | | -------------> Gene 2 (Even with waypoints this problem can exist) The proposed solution is to calcuate the direction of the connectors at the start and end-point automatically. The direction is determined by the partiuclar anchor user has chosen to use (east or south anchors were used in the examples above). This can be programmatically checked as follows (pseudo-code): relx = connector.startx - shape.centerx rely = connector.starty - shape.centery if (abs (relx) > abs (rely)) { if (relx > 0) direction = east else direction = west } else { if (rely > 0) direction = south else direction = north } * AP: Nice job catching this subtle problem. I wasn't sure I understood the solution, so I added a clarifying sentence above (please double check). As an alternative, I thought you might be able just label the anchors (N,S,E,W) so you could skip the explicit calculation, but then I realised that if the shape were rotated, these labels would have to be re-calculated anyways, so it doesn't help. * AP: How would this work for anchors on lines, where there is no shape.center(x or y)? == Curved connectors == Because people can't seem to live without them, we will also add support for a curved bend style: Gene 1 -- \ | + | \ --> Gene 2 This will be similar to the elbow bends, but now the line will curve smoothly through the waypoint(s). AP: I assume this would generate a simple curved line when there are no waypoints? We need to make sure we are also supporting this type of line: __ / \ Gene 1 Gene 2 TK: It will be represented like this: --+-- / \ Gene 1 Gene 2 The waypoint will be inserted automatically, and the user can modify its position (see curves in Powerpoint). == Changes to GPML == We will introduce the following new attributes and elements: - Line.Type = [straight, elbow, curved] The connector type, 'straight' will be default. - Line.Anchor Optional line anchor point (a line may have multiple anchor points). - Line.Anchor.X The coordinate of the anchor point (relative to the line). - Line.Anchor.GraphId The GraphId of the anchor point. - Line.Waypoint A waypoint for the elbow/curved connector. - Line.Waypoint.Position The position of the waypoint. Depending on the directon of the segment this will be the x or y coordinate through which the segment will be drawn. All are optional, so the changes will be backwards compatible. Here's an example of the GPML code: Which will be drawn like this: Gene 3 | v Gene1 --o--- | + | -----> Gene 2 * AP: I altered the diagram and waypoint position to match better (the waypoint X was to the right of the anchor, though both were at X=300). * AP: Line.Anchor.X should be renamed to Line.Anchor.Position (because it is not an X coordinate) * TK: Good point, I changed it == GUI behaviour == In this section discuss on GUI behavior as result of user actions (e.g. what would happen if I do this or that). It will be a real challenge to code the GUI behaviour correctly, but we should be sure that we excactly specified how the GUI will respond to these kind of actions before we start coding. So any more comments on this part are welcome. === Action: change object anchor === * AP: To make sure I understand: In the above GPML example, what would happen if the user were to move the connector start to the South anchor on Gene 1? Would the anchor on Gene 2 change to north and would the waypoint position "350" refer to the Y coord instead of the X? And what happens to Gene 3. It's hard to draw, but I presume it would stay in its place (300,100) and an off-grid, sloping line would connect it to the new anchor position (200,300). Gene 1 | o |--------+-------- | \/ Gene 2 * TK: I'm not sure if we should change the anchor on Gene 2 to North, the anchor position of an object should be independent of other objects. What I had in mind would rather look like this: Gene 3 | Gene1 | | | o<------ | --------------> Gene 2 There will be no extra bend anymore, so the waypoint will just dissapear. The connector from Gene 3 would just reroute to the new position of the line anchor (depending on the style, in this case it's an elbow connector). If you want the same end result as in your example, you can move the anchor on Gene 2 to north: Gene 3 | Gene1 -+-| | v -----o---+--------- | Gene 2 Note that the connector from Gene 3 reroutes again. In this case the waypoint indeed refers to an Y coordinate, in this example it will be 350, but that doesn't have to be. In the proposal, the waypoint positions would be absolute coordinates which are calculated by the view upon changing the connector. Maybe it should be relative coordinates that remain the same when you change the number of segments of the connector. It could be the relative distance from the first object (so 0.5 would be the center), for example: waypoint1: 0 waypoint2: 0 Gene1 ------------- | | v Gene 2 waypoint1: 0,5 waypoint2: 0 Gene1 ------ | + | ---->Gene 2 waypoint1: 1.2 waypoint2: 0 Gene1 ------------------- | + | Gene2 <-- waypoint1: 0.5 waypoint2: 1.2 Gene1 ---- | | + Gene2 | | |----+---- == Point coordinates of connectors == In the current implementation, line ends are not really linked to an object anchor, but have their own coordinates which need to be updated when moving the object. Maybe it would be better to store the coordinate relative to the object when a point is part of a connector. So in this case, there are two types of coordinates: 1. The point has no GraphRef (no connector), the coordinates X and Y are used, they are relative to the canvas 2. The point has a GraphRef (connector), the coordinates RelX and RelY are used, they are relative to the object to which is linked This way we don't have to update all linked points every time an object is moved. The object then doesn't need to have a notion of linked points, which improves modularity and performance. The xsd needs to change to handle these relative coordinates. This can be done as follows: becomes Points that do not have a graphId can still use X and Y attributes. Points that do have a graphId have to use RelX and RelY. You can either specify X and Y but not GraphId or RelX and RelY and GraphId. This will be enforced in GPML.xsd. For backwards compatibility, we can support reading X and Y and GraphId, but then immediately the relative coordinates are calculated and used for writing. (I think relative coordinates may also be useful for groups...) * AP: Hmm.. Does this affect how GMPL would be read by other programs, like Cytoscape? I worry about the same tag having two different meanings. I'm not sure the extra parsing requirements (which may be relevant to multiple apps in the future) are worth the programmatic updates to line coords (which are relevant only to PathVisio, which we have better control over). * TK: I'm sorry, the first lines of this section weren't updated with Martijn's modifications. He introduced the RelX and RelY, attributes. In this case the attributes have unique meanings, they just can't co-exist. Does this solve the problem? == Changes to the code == TODO