3

I would like to link two divs (left edge of a2 and left edge of b1) with line. I have found that one of the ways is to use svg element and I tried to do that in vain.

The expected result is: enter image description here

There are two problems:

  1. The link has to be added dyamically so I tried to use javascript but something does not work. If I place the value of elementToAppend to the mySvg manually - the line display and there are two lines in the html source of the page but only one is displayed.

  2. If the line is added manually - the element fromElement is linked to the toElement with blue line. The problem is that this line is relative to the whole screen, not the container container that is scrollable (it has to be scrollable). So whe user scrolls the container - the line does not scroll and stay on the same place.

My code is:

<html>
    <head>
        <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    </head>
    <body>
        <div id="customHeader">custom header</div>

        <div id="container"> 
            <div id="firstRow">
                <div class="elementA">a1</div>
                <div class="elementA">a2</div>
                <div id="fromElement" class="elementA">a3</div>
                <div class="elementA">a4</div>
                <div class="elementA">a5</div>
                <div class="elementA">a6</div>
                <div class="elementA">a7</div>
                <div class="elementA">a8</div>
                <div class="elementA">a9</div>
            </div>
            <div id="secondRow">
                <div class="elementB">b1</div>
                <div id="toElement" class="elementB">b2</div>
                <div class="elementB">b3</div>
                <div class="elementB">b4</div>
                <div class="elementB">b5</div>
                <div class="elementB">b6</div>
                <div class="elementB">b7</div>
                <div class="elementB">b8</div>
                <div class="elementB">b9</div>
            </div>      
        </div>
        <svg id="mySvg">
        </svg> 
    </body>
    
    <script>
        $(function(){
            linkElements();
        });
        
        function linkElements(){
            var fromHeight = $("#fromElement").position().top - $("#fromElement").height()/2;
            var fromLeft = $("#fromElement").position().left;
            var toHeight = $("#toElement").position().top - $("#toElement").height()/2;
            var toLeft = $("#toElement").position().left;
            var middleVertical = toHeight - fromHeight;
            var middleHorizontal = toLeft - fromLeft;
            var elementToAppend = "<path d='M " + fromLeft + " " + fromHeight + " L " + toLeft + " " + toHeight + "' stroke='blue' strine-width='5' fill='none' />";
            console.log(elementToAppend)
            $("#mySvg").append(elementToAppend);
        }
        
    </script>
    
    <style>
        #mySvg{
            position:absolute;
            top:0px;
            left:0px;
            width:100%;
            height:100%;
        }
        #customHeader{
            width: 100%;
            height: 100px;
            background: grey;
            text-align: center;
        }   
        #container{
            overflow: auto;
            display: flex;
            height: 500px;
        }
        #secondRow, #firstRow{
            float: left;
            flex: 1;
            height: 100%;
            margin-left: 20px;
            margin-right: 20px;
        }
        .elementA, .elementB{
            margin-top: 20px;
            margin-bottom: 20px;
            width: 100%;
            height: 100px;
            background: red;
            text-align: center;
        }
    </style>
</html>

What is the best way to solve that problem?

Rash J
  • 133
  • 1
  • 9
  • There is a smilar question here with working snippet answers https://stackoverflow.com/questions/39720603/how-to-draw-responsive-lines-between-divs/40490332#40490332 - may be adaptable if you could use it? – Vanquished Wombat Nov 23 '20 at 21:50

1 Answers1

1

The problem is that the line linking two elements is showing when it is added manually, but not when it is added by Javascript. elementToAppend is actually a string, not an element object, so you don't want to append it into the SVG element, you need instead to put it into the SVG element's innerHTML.

So remove this line:$("#mySvg").append(elementToAppend);

and replace with: document.getElementById("mySvg").innerHTML = elementToAppend;

Also to recalculate the line when the window is altered an onresize event is senses in the body element.

<html>
    <head>
        <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    </head>
    <body onresize="linkElements()">
        <div id="customHeader">custom header</div>

        <div id="container"> 
            <div id="firstRow">
                <div class="elementA">a1</div>
                <div class="elementA">a2</div>
                <div id="fromElement" class="elementA">a3</div>
                <div class="elementA">a4</div>
                <div class="elementA">a5</div>
                <div class="elementA">a6</div>
                <div class="elementA">a7</div>
                <div class="elementA">a8</div>
                <div class="elementA">a9</div>
            </div>
            <div id="secondRow">
                <div class="elementB">b1</div>
                <div id="toElement" class="elementB">b2</div>
                <div class="elementB">b3</div>
                <div class="elementB">b4</div>
                <div class="elementB">b5</div>
                <div class="elementB">b6</div>
                <div class="elementB">b7</div>
                <div class="elementB">b8</div>
                <div class="elementB">b9</div>
            </div>      
        </div>
        <svg id="mySvg">
        </svg> 
    </body>
    
    <script>
        $(function(){
            linkElements();
        });
        
        function linkElements(){
            var fromHeight = $("#fromElement").position().top - $("#fromElement").height()/2;
            var fromLeft = $("#fromElement").position().left;
            var toHeight = $("#toElement").position().top - $("#toElement").height()/2;
            var toLeft = $("#toElement").position().left;
            var middleVertical = toHeight - fromHeight;
            var middleHorizontal = toLeft - fromLeft;
            var elementToAppend = "<path d='M " + fromLeft + " " + fromHeight + " L " + toLeft + " " + toHeight + "' stroke='blue' strine-width='5' fill='none' />";
            console.log(elementToAppend)
            //$("#mySvg").append(elementToAppend);
            document.getElementById("mySvg").innerHTML = elementToAppend;
        }
        
    </script>
    
    <style>
        #mySvg{
            position:absolute;
            top:0px;
            left:0px;
            width:100%;
            height:100%;
        }
        #customHeader{
            width: 100%;
            height: 100px;
            background: grey;
            text-align: center;
        }   
        #container{
            overflow: auto;
            display: flex;
            height: 500px;
        }
        #secondRow, #firstRow{
            float: left;
            flex: 1;
            height: 100%;
            margin-left: 20px;
            margin-right: 20px;
        }
        .elementA, .elementB{
            margin-top: 20px;
            margin-bottom: 20px;
            width: 100%;
            height: 100px;
            background: red;
            text-align: center;
        }
    </style>
</html>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • There is still the second problem, I mean that the line is not relative to the scrollable container (ale this line is always on the same place on the screen, not on the same place on the container) – Rash J Nov 23 '20 at 21:53
  • That's because it isn't being recalculated on a window resize. I have put an onresize event into the body element which calls linkElements each time. Does that solve the problem? – A Haworth Nov 23 '20 at 22:20