Creating a link based on a cubic bezier path

477 views
Skip to first unread message

Aidan Reel

unread,
Sep 16, 2013, 7:48:34 AM9/16/13
to joi...@googlegroups.com

Hi

 

I wish to have a link that is shaped as elongated S using cubic Bezier curve.

 

I see it working by having an SVG path using the C or c (cubic command) with the control points being defined as follows

P1 : source(x,y).

P2 : x= (P4.x – P1.x) / 2, y=p1.y

P3:  x= (P4.x – P1.x) / 2, y=P4.y

P4 : target(x,y)

Where P2 and P3 get updated as the source and target nodes get moved.

The current smooth links have static values for vertices which I havent seen how to adjust based on source or target points changing.

I have taken a look in the source code to see what is available and how things currently work and want to confirm the following:

  • Current smooth links do not use the svg cubic Bezier  functionality of paths (C and c) but the Bezier code from the geometry library which uses a through control points approach.
  • If I were to go ahead and implement this type of link, I could still subclass from joint.dia.link but disable all the vertices code, introduce C commands to the Path and update the C command values in the target/source changed event handlers. Or would you recommend something else?

Cheers

Aidan




dave

unread,
Sep 16, 2013, 12:34:31 PM9/16/13
to joi...@googlegroups.com
Hi Aidan,

the current smooth link actually uses cubic bezier curve ('C' path commands) such that the resulting curve goes though the vertices defined on the link model. However, if there is no vertex in the vertices array, the resulting curve is straight. I assume that you would prefer to have a curved line even though there is no vertex in the vertices array. Am I correct? If yes, than it seems to me like a good enhancement of JointJS. One can assume that if he wants to have a smooth link and there are no vertices set on the link model, still, it makes sense to draw the link as a curvy path. 

We'd be happy if you could create a pull request in Github implementing just that. The only place that needs an update is (I believe) in the joint.dia.link.js: getPathData() function. Inside the branch that checks the smooth flag, you could do something like:
...
        if (this.model.get('smooth')) {
            if (vertices && vertices.length) {     
                d = g.bezier.curveThroughPoints([sourcePoint].concat(vertices || []).concat([targetPoint]));           
            } else {
                d = here assign an array of SVG path commands defining a cubic bezier based on sourcePoint and targetPoint
            }
        } else {
...

Let us know if you need more help.

Cheers,
Dave

Aidan Reel

unread,
Sep 16, 2013, 7:45:50 PM9/16/13
to joi...@googlegroups.com
Hi Dave,

Thanks for the clarification, focused on the "curveThroughPoints" and missed the meaning of the d variable.

Yes you are correct having the line curved by default would answer my needs.

I made the change you suggested and it has tested out well.
There is one more issue that I might need to add before making the pull request.

I have a triangle marker at the end of the link, this is moving around the target magnet as I move the element, I would like it to stay perpendicular to the magnet.

Is this something that I could add or is it already available via some configuration option?

Cheers

Aidan

dave

unread,
Sep 17, 2013, 4:23:26 AM9/17/13
to joi...@googlegroups.com
Aidan, I think the problem now is that the triangle marker is auto-oriented towards the opposite (source or target) object instead of towards a close point on the curvy path. This is something you have to tell the LinkView how to do it. There are two places in joint.dia.link.js that this is being done:

1. update() method: for the source/target markers (the visible arrowheads):
        this._markerSource.translateAndAutoOrient(sourcePosition, firstVertex || targetPosition, this.paper.viewport);
    this._markerTarget.translateAndAutoOrient(targetPosition, lastVertex || sourcePosition, this.paper.viewport);

2. renderArrowheadMarkers(): for the 'handles' that appear when the link is being hovered:
        V(sourceArrowhead).translateAndAutoOrient(sourcePosition, firstVertex || targetPosition, this.paper.viewport);
    V(targetArrowhead).translateAndAutoOrient(targetPosition, lastVertex || sourcePosition, this.paper.viewport);

The vectorizer's translateAndAutoOrient() function provides a facility similar to what native SVG markers do when the orient=auto attribute is set on them. The reason we don't use native SVG markers is that they cannot be accessed through the DOM. That's why we use <path> elements for arrowheads and have our own translateAndAutoOrient() method. This method has the following signature and can be found in src/vectorizer.js:

translateAndAutoOrient(position, reference, target);

Where position is the point the arrowhead should point to (usually on the boundary of the source/target objects). reference is another point that is used to calculate the orientation of the arrowhead (its rotation). E.g. if the position is somewhere in the center of the screen and the reference is horizontally to the left of the position, the arrowhead would point to the right "touching" the position. The last argument is the target which is an element relative to which transformations are applied. You don't have to worry about this last argument, it is always the paper.viewport.

Long story short, your challenge would be to find the reference point. Does this make sense to you?

Aidan Reel

unread,
Sep 17, 2013, 11:41:10 AM9/17/13
to joi...@googlegroups.com
Yes I think I do.
In meantime I will do the bezier change.
Reply all
Reply to author
Forward
0 new messages