Search Unity

Any good way to draw lines between UI elements?

Discussion in 'UGUI & TextMesh Pro' started by yoonitee, Apr 10, 2015.

  1. yoonitee

    yoonitee

    Joined:
    Jun 27, 2013
    Posts:
    2,363
    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?
     
    TheDarkVoice likes this.
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Check out this user contributed script for drawing lines in the new UI system (http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/) 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
     
  3. TheDarkVoice

    TheDarkVoice

    Joined:
    Jan 31, 2016
    Posts:
    3
    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.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. public class LineBetweenObjects : MonoBehaviour
    5. {
    6.     private RectTransform object1;
    7.     private RectTransform object2;
    8.     private Image image;
    9.     private RectTransform rectTransform;
    10.     // Start is called before the first frame update
    11.     void Start()
    12.     {
    13.         image = GetComponent<Image>();
    14.         rectTransform = GetComponent<RectTransform>();
    15.     }
    16.  
    17.     public void SetObjects(GameObject one, GameObject two)
    18.     {
    19.         object1 = one.GetComponent<RectTransform>();
    20.         object2 = two.GetComponent<RectTransform>();
    21.  
    22.         RectTransform aux;
    23.         if (object1.localPosition.x > object2.localPosition.x)
    24.         {
    25.             aux = object1;
    26.             object1 = object2;
    27.             object2 = aux;
    28.         }
    29.     }
    30.     // Update is called once per frame
    31.     void Update()
    32.     {
    33.         if (object1.gameObject.activeSelf && object2.gameObject.activeSelf)
    34.         {
    35.             rectTransform.localPosition = (object1.localPosition + object2.localPosition) / 2;
    36.             Vector3 dif = object2.localPosition - object1.localPosition;
    37.             rectTransform.sizeDelta = new Vector3(dif.magnitude, 5);
    38.             rectTransform.rotation = Quaternion.Euler(new Vector3(0, 0, 180 * Mathf.Atan(dif.y / dif.x) / Mathf.PI));
    39.         }
    40.     }
    41. }
    42.  
     
  4. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    That works like a charm. Here's my version, which dynamically creates the lines:

    Code (CSharp):
    1.     void MakeLine(float ax, float ay, float bx, float by, Color col) {
    2.         GameObject NewObj = new GameObject();
    3.         NewObj.name = "line from "+ax+" to "+bx;
    4.         Image NewImage = NewObj.AddComponent<Image>();
    5.         NewImage.sprite = lineImage;
    6.         NewImage.color = col;
    7.         RectTransform rect = NewObj.GetComponent<RectTransform>();
    8.         rect.SetParent(transform);
    9.         rect.localScale = Vector3.one;
    10.  
    11.         Vector3 a = new Vector3(ax*graphScale.x, ay*graphScale.y, 0);
    12.         Vector3 b = new Vector3(bx*graphScale.x, by*graphScale.y, 0);
    13.  
    14.  
    15.         rect.localPosition = (a + b) / 2;
    16.         Vector3 dif = a - b;
    17.         rect.sizeDelta = new Vector3(dif.magnitude, lineWidth);
    18.         rect.rotation = Quaternion.Euler(new Vector3(0, 0, 180 * Mathf.Atan(dif.y / dif.x) / Mathf.PI));
    19.    }
    20.  
    Note that you need to make sure the anchor points are set correctly. My graph starts bottom left, so I add:

    Code (CSharp):
    1.         // set them to start bottom-left
    2.         rect.anchorMin = Vector2.zero;
    3.         rect.anchorMax = Vector2.zero;
    4.  
    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.
     
    Rachan and Strom_CL like this.
  5. MichaelEGA

    MichaelEGA

    Joined:
    Oct 11, 2019
    Posts:
    40
    Thanks, I used a version of this in my game. Works well.