stathissideris / dali

dali is a Clojure library for representing, exporting and manipulating the SVG graphics format.
295 stars 16 forks source link

Smarter connector types #16

Open setzer22 opened 5 years ago

setzer22 commented 5 years ago

Hi, first of all, thanks for this awesome library!

After using the connector layout, I feel there is a missing feature. First of all, as a minor introduction, I'm working on a library to dynamically layout flowchart-like diagrams. Because of the dynamic nature of the generation, I do not know a priori where my elements will end up being.

I've encountered an issue when creating what I call a "split" path. Please see the following picture: image

As you can see, after the diamond-shaped node, the flow "forks" into three different branches. This is how I want my diagram to look. However, when generating the diagram, I have no way to know if one of the branches (in this case, the one containing B) will be horizontally align with the diamond. So I cannot decide at generation type if I want a :-- or a :|- connector. If I use the :|- type in all branches, I end up with this: image

Now, as I understand, this kind of information cannot be obtained at the diagram generation time, because the document has not been rendered yet, so my idea was to extend the connector types with a "smart connection" one, that will either choose a straight or an angle connector, depending on the slope between the two elements (a configurable parameter). Do you think this is a viable approach?

I'm willing to work on a PR myself, but some guidance would be very much appreciated!

Thanks!

setzer22 commented 5 years ago

I made this (very very simple) version of the functionality that works for me. The new connector types are :?- and :-?, and will substitute the "?" with "|" or "-" depending on whether the angle between the two elements is too steep.

Note that this version only works for horizontal connections, because I check the y coordinate difference and not the angles. Also epsilon is hard-coded but should be added as a parameter. It works for my case, but if anyone's interested I can clean it up, make it more generic and submit as a PR!

(defn- smart-connector [start-element end-element attrs connection-type bounds-fn]
  (let [[_ [x1 y1] [w1 h1]] (bounds-fn start-element)
        [_ [x2 y2] [w2 h2]] (bounds-fn end-element)
        cy1 (+ y1 (/ h1 2))
        cy2 (+ y2 (/ h2 2))
        epsilon 20.0]
    (if (< (Math/abs (- cy1 cy2)) epsilon)
      (straight-connector start-element end-element attrs bounds-fn)
      (corner-connector start-element end-element attrs
                        ({:?- :|-, :-| :-?} connection-type)
                        bounds-fn))))
stathissideris commented 5 years ago

Apologies for the delay. I think this is certainly useful functionality that could be part of dali. I'm not so sure about the names of the new types, I can see how you arrived to them, but they may be a bit obscure/scary.

Also, about how you decide on what connection type to use: The vertical center of the end element might be much higher than the vertical center of the start element, so you could decide on :-|, but if the end element is very tall, this type of connection would be inappropriate. I think we may need a more sophisticated way to select the type.