Any good way to draw lines between UI elements?

Say I have a few draggable image elements. I want to draw some lines between them, like a flow chart or a family tree type structure. Do you know of a good way to do this?

My thoughts are my options:

  • Draw a think black rotated image to act as a line
  • Draw an image and set the pixels of the image to draw a line say from top-left to bottom-right
  • Use GL.Line
  • Draw 100 tiny images of circles lines up in a line or curve
  • Draw many short rotated thin line images to make a curved line

Which do you think is best and fastest?

1 Like

Check out this user contributed script for drawing lines in the new UI system (New UI and line drawing - Unity Engine - Unity Discussions) not added it to the UI Extension repo yet (link in sig) but working on it.

Alternatively, if you want to draw lines outside of UI, then use one of the native Line Renderer components

Hey there, I had the same problem and I solved it by drawing a thick black rotated image :))
Works only between 2 objects, but can be easily extended
Here is the code, if anyone needs it:
You have to call the SetObjects function and give as parameters 2 gameObjects that have rect transform attached to them.

using UnityEngine;
using UnityEngine.UI;

public class LineBetweenObjects : MonoBehaviour
{
    private RectTransform object1;
    private RectTransform object2;
    private Image image;
    private RectTransform rectTransform;
    // Start is called before the first frame update
    void Start()
    {
        image = GetComponent<Image>();
        rectTransform = GetComponent<RectTransform>();
    }

    public void SetObjects(GameObject one, GameObject two)
    {
        object1 = one.GetComponent<RectTransform>();
        object2 = two.GetComponent<RectTransform>();

        RectTransform aux;
        if (object1.localPosition.x > object2.localPosition.x)
        {
            aux = object1;
            object1 = object2;
            object2 = aux;
        }
    }
    // Update is called once per frame
    void Update()
    {
        if (object1.gameObject.activeSelf && object2.gameObject.activeSelf)
        {
            rectTransform.localPosition = (object1.localPosition + object2.localPosition) / 2;
            Vector3 dif = object2.localPosition - object1.localPosition;
            rectTransform.sizeDelta = new Vector3(dif.magnitude, 5);
            rectTransform.rotation = Quaternion.Euler(new Vector3(0, 0, 180 * Mathf.Atan(dif.y / dif.x) / Mathf.PI));
        }
    }
}
5 Likes

That works like a charm. Here’s my version, which dynamically creates the lines:

    void MakeLine(float ax, float ay, float bx, float by, Color col) {
        GameObject NewObj = new GameObject();
        NewObj.name = "line from "+ax+" to "+bx;
        Image NewImage = NewObj.AddComponent<Image>();
        NewImage.sprite = lineImage;
        NewImage.color = col;
        RectTransform rect = NewObj.GetComponent<RectTransform>();
        rect.SetParent(transform);
        rect.localScale = Vector3.one;

        Vector3 a = new Vector3(ax*graphScale.x, ay*graphScale.y, 0);
        Vector3 b = new Vector3(bx*graphScale.x, by*graphScale.y, 0);


        rect.localPosition = (a + b) / 2;
        Vector3 dif = a - b;
        rect.sizeDelta = new Vector3(dif.magnitude, lineWidth);
        rect.rotation = Quaternion.Euler(new Vector3(0, 0, 180 * Mathf.Atan(dif.y / dif.x) / Mathf.PI));
   }

Note that you need to make sure the anchor points are set correctly. My graph starts bottom left, so I add:

        // set them to start bottom-left
        rect.anchorMin = Vector2.zero;
        rect.anchorMax = Vector2.zero;

as the last lines of that function.

The function above uses a few global variables to scale and set line width, etc. but it should be easy enough to figure it out. I pass in parameters as individual floats because that’s how I get my data, but you could easily adapt it to accept a Vector3.

2 Likes

Thanks, I used a version of this in my game. Works well.