2

i am working around a cola.js example enter link description here

and i added markers (arrows) a the end of the links. However, since the nodes are rectangular are overlaping the arrows. I tried to fix it by changing 'refX' of marker but is not looking good.

The code of the marker is :

// define arrow markers for graph links
    svg.append('svg:defs').append('svg:marker')
    .attr('id', 'end-arrow')
        .attr('viewBox', '0 -5 10 10')
        .attr('refX', 30)
        //.attr("refY", -1.5)
        .attr('markerWidth', 6)
        .attr('markerHeight', 6)
        .attr('orient', 'auto')
        .append('svg:path')
        .attr('d', 'M0,-5L10,0L0,5')
        .attr('fill', '#000');

and then add it in the end of link:

` cola.on("tick", function () {

        link.attr("x1", function (d) { return d.source.x; })
            .attr("y1", function (d) { return d.source.y; })
            .attr("x2", function (d) { return d.target.x; })
            .attr("y2", function (d) { return d.target.y; })
            .attr("marker-end","url(#end-arrow)");  
`
galatia
  • 473
  • 1
  • 5
  • 18
  • i manage to make it a bit better by changing the code in the tick function : cola.on("tick", function () { link.attr("x1", function (d) { return d.source.x; }) .attr("y1", function (d) { return d.source.y; }) .attr("x2", function (d) { if((d.source.x - d.target.x)>0){ return d.target.x+25; }else{ return d.target.x-25; } }) .attr("y2", function (d) { return d.target.y; }) .attr("marker-end","url(#end-arrow)"); – galatia Sep 24 '18 at 08:16

2 Answers2

0

If i may recommend another way to create your edges.

Following this example here - disclaimer it seems the actual example is broken due to what im assuming is a typo in the code.

long story short. the important part is this inside your cola.on("tick" function(){

            link.each(function (d) {
            d.route = cola.makeEdgeBetween(d.source.innerBounds, d.target.innerBounds, 5);
        });

        link.attr("x1", d => d.route.sourceIntersection.x)
            .attr("y1", d => d.route.sourceIntersection.y)
            .attr("x2", d => d.route.arrowStart.x)
            .attr("y2", d => d.route.arrowStart.y);

the third argument (5) for makeEdgeBetween, if i'm not mistaken, is spacing to take into account your arrowhead length, if you look at the source it should be called ah. And im pretty sure the makeEdgeBetween function will create the edge up until the rectangular boundary of the node, instead of the centre

theya
  • 33
  • 2
  • 8
0

Had the same issue, but I took a different approach. I did not like having the arrowhead only on the sides, so I made a function to calculate the relative positions of the target and source nodes and place the link targets accordingly.

function calculateRelativePosition(d){
        let relative = {"x2":0,"y2":0};
        const pixels = 3;
        const relativex = d.source.x - d.target.x;
        const relativey = d.source.y - d.target.y;

        if(Math.abs(relativex) > Math.abs(relativey)){
            if((d.source.x - d.target.x)>0)
            {
                relative.x2 = d.target.x + d.target.width /2 - pad +pixels;
                relative.y2 = d.target.y;
                return relative;
            }
            else
            {
                relative.x2 = d.target.x- d.target.width/2  + pad - pixels;
                relative.y2 = d.target.y;
                return relative;

            }
        }
        if((d.source.y - d.target.y)>0)
        {
            relative.x2 = d.target.x
            relative.y2 = d.target.y + d.target.height /2 - pad + pixels
            return relative;

        }
        else
        {
            relative.x2 = relative.x2 = d.target.x;
            relative.y2 = d.target.y - d.target.height/2  + pad - pixels
            return relative;
        }

    }

Then on the cola.on("tick")

 cola.on("tick", function () {
        
        link.attr("x1", function (d) { return d.source.x; })
            .attr("y1", function (d) { return d.source.y; })
            .attr("x2", function (d) { return calculateRelativePosition(d).x2 })
            .attr("y2", function (d) { return calculateRelativePosition(d).y2 });

The method will compare the relative position of the nodes and will place the arrowhead in one of the 4 sides of the rectangle, the one with the least angular distance to the other node.

Marsson
  • 687
  • 7
  • 16