I'm using the NGX Graph 'linkTemplate' to add circle in the middle of the link(Edge) but alignment is missing. I'm using transform property to align the circle in the middle of link. How to calculate exact coordinates to place the circle(with icon) in the middle of the link?
Here my code for the above graph
<ngx-graph
class="chart-container"
[view]="[990, 800]"
[curve]="curve"
[draggingEnabled]="false"
[autoCenter]="true"
[links]="links"
[nodes]="nodes">
<ng-template #defsTemplate>
<svg:marker id="arrow-yellow" fill="#f49600" viewBox="0 -5 10 10" refX="8" refY="0" markerWidth="6" markerHeight="6" orient="auto">
<svg:path d="M0,-5L10,0L0,5" class="arrow-head"/>
</svg:marker>
<svg:marker id="arrow" fill="#262626" viewBox="0 -5 10 10" refX="8" refY="0" markerWidth="6" markerHeight="6" orient="auto">
<svg:path d="M0,-5L10,0L0,5" class="arrow-head"/>
</svg:marker>
</ng-template>
<ng-template #nodeTemplate let-node>
<svg:g class="node">
<svg:rect
[attr.width]="node.dimension.width + 5"
[attr.height]="node.dimension.height - 1"
[attr.fill]="node.isSelected ? '#FFB716' : '#f6f6f6'"
[attr.stroke-width]="1"
[attr.stroke]="node.isSelected ? '#f49600' : '#262626'"/>
<svg:text alignment-baseline="central" [attr.x]="10" [attr.y]="node.dimension.height / 2" [attr.letter-spacing]="0.5">
{{node.label}}
</svg:text>
</svg:g>
<svg:g class="assignNode" [attr.transform]="'translate(' + (node.dimension.width - 1) + ',' + 0 + ')'">
<circle cx="5" cy="5" r="9" [attr.stroke]="node.isSelected ? '#f49600' : '#262626'" stroke-width="1" fill="white" />
<path id="assign" viewBox="0 0 5 5" d="M9.88.15a.53.53,0,0,0-.67,0h0L8.05,1.32a4,4,0,0,0-5.27.33l-.5.44,0,.06V2.2a.06.06,0,0,0-.06.06l-.5.44A4,4,0,0,0,1.34,8L.17,9.13l-.05.06a.45.45,0,0,0,.05.66.46.46,0,0,0,.67,0L2,8.63A4,4,0,0,0,7.27,8.3l.5-.5.05,0a.06.06,0,0,0,.06-.06l.5-.5a4,4,0,0,0,.33-5.26L9.88.76A.45.45,0,0,0,9.88.15ZM6.6,7.69a2.94,2.94,0,0,1-4.26,0,3.06,3.06,0,0,1-.06-4.32l.17-.17L6.72,7.47ZM7.71,6.58l-.16.17L3.22,2.43l.17-.17a3,3,0,0,1,4.27,0A3.05,3.05,0,0,1,7.71,6.58Z" />
</svg:g>
</ng-template>
<ng-template #linkTemplate let-link>
<svg:g [attr.class]="link.isLinkActive ? 'active edge': 'notActive edge'">
<svg:path class="line" *ngIf="!link.isLinkActive" stroke-width="1" marker-end="url(#arrow)"></svg:path>
<svg:path class="line" *ngIf="link.isLinkActive" stroke-width="1" marker-end="url(#arrow-yellow)"></svg:path>
</svg:g>
<svg:g class="deAssignEdge" (click)="onDeAssingEvent(link)" *ngIf="link.midPoint" [attr.transform]="'translate(' + (link.midPoint.x) + ',' + (link.midPoint.y) + ')'">
<circle cx="5" cy="5" r="9" [attr.stroke]="link.isLinkActive ? '#f49600': '#262626'" stroke-width="1" fill="white" />
<path d="M6.26,6.89l-.6-.6-2-2-.55-.6-.6-.55a.45.45,0,0,0-.61,0l-.38.44a3.51,3.51,0,0,0-.27,4.61l-1,1h0a.43.43,0,0,0,0,.6.43.43,0,0,0,.61,0l1-1a3.45,3.45,0,0,0,4.61-.27l.43-.44a.42.42,0,0,0,0-.6Zm-.44,1A2.64,2.64,0,0,1,2.09,4.15L2.26,4,6,7.71Z" />
<path d="M9.83.15a.43.43,0,0,0-.61,0h0l-1,1a3.45,3.45,0,0,0-4.61.27l-.38.44h0a.5.5,0,0,0,0,.55L4.51,3.77l-.39.33.44.43.33-.33L5.71,5l-.27.38.44.44.33-.33L7.47,6.78a.42.42,0,0,0,.6,0l.44-.44a3.44,3.44,0,0,0,.27-4.6l1.05-1A.36.36,0,0,0,9.83.15ZM8,5.8,7.8,6,4.07,2.18,4.23,2A2.62,2.62,0,0,1,8,2,2.69,2.69,0,0,1,8,5.8Z" />
</svg:g>
</ng-template>
</ngx-graph>
public links = [
{
id: 'a',
source: 'first',
target: 'second',
label: 'is parent of',
isLinkActive: false,
sourceIndex:1
},
{
id: 'b',
source: 'first',
target: 'third',
label: 'custom label',
isLinkActive: false,
sourceIndex:2
},
{
id: 'c',
source: 'second',
target: 'Four',
label: 'custom label',
isLinkActive:true,
sourceIndex:1
},
{
id: 'd',
source: 'second',
target: 'Five',
label: 'custom label',
isLinkActive:true,
sourceIndex:2
},
{
id: 'e',
source: 'second',
target: 'Six',
label: 'custom label',
isLinkActive:true,
sourceIndex:3
},
{
id: 'f',
source: 'second',
target: 'Seven',
label: 'custom label',
isLinkActive:true,
sourceIndex:4
},
{
id: 'g',
source: 'third',
target: 'Eight',
label: 'custom label',
isLinkActive: false,
sourceIndex:1
},
{
id: 'h',
source: 'third',
target: 'Nine',
label: 'custom label',
isLinkActive: false,
sourceIndex:2
},
{
id: 'i',
source: 'third',
target: 'Ten',
label: 'custom label',
isLinkActive: false,
sourceIndex:3
},
{
id: 'j',
source: 'Four',
target: 'Ele',
label: 'custom label',
isLinkActive: false,
sourceIndex:1
},
{
id: '1',
source: 'Ele',
target: 'Four',
label: 'custom label',
isLinkActive: false,
sourceIndex:1
}
];
public nodes = [
{
id: 'first',
label: 'AAAAAAA',
isSelected:false,
},
{
id: 'second',
label: 'BBBBB',
isSelected:true,
},
{
id: 'third',
label: 'CCCC',
isSelected:false
},
{
id: 'Four',
label: 'DDDD',
isSelected:false
},
{
id: 'Five',
label: 'EEEEE',
isSelected:false
},
{
id: 'Six',
label: 'FFFF',
isSelected:false
},
{
id: 'Seven',
label: 'GGGG',
isSelected:false
},
{
id: 'Eight',
label: 'HHH',
isSelected:false
},
{
id: 'Nine',
label: 'III',
isSelected:false
},
{
id: 'Ten',
label: 'JJJ',
isSelected:false
},
{
id: 'Ele',
label: 'KKKKKKK',
isSelected:false
}
]
Stackblitz link: https://stackblitz.com/edit/ngx-graph-demo-quawhu
Based on this answer you could call a method which returns the mid point of the path by creating a svg element with the same path as the one from the link (link.line
) and get the middle of the path like so:
getXYForCenteredLinkCircle(link: Edge): [number, number] {
var myPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
myPath.setAttributeNS(null, "d", link.line);
var length = myPath.getTotalLength();
let p = myPath.getPointAtLength(length / 2);
return [p.x - 5, p.y - 5]; // Consider the center coordinates of the circle
}
And in the template:
<svg:g [attr.transform]="'translate(' + getXYForCenteredLinkCircle(link)[0] + ',' + getXYForCenteredLinkCircle(link)[1] + ')'">
It will look like this: