<div style="position:absolute; left:0; top:0; width: 100px; height: 50px; background:red;"></div>
<div style="position:absolute; left:250px; top:150px; width: 100px; height: 50px; background: blue;"></div>
<svg style="position:absolute; left:0; top:0;" width="300" height="300">
<line x1="100" y1="50" x2="250" y2="150" stroke="black"/>
</svg>
Example:
In app.component.html file:
<div class="cont">
<div *ngFor="let item of arr_item; index as i" class="block d-flex align-items-center justify-content-between">
<div class="d-flex flex-column" #left>
<div *ngFor="let val of item.left" class="box box-left">
{{val}}
</div>
</div>
<div class="d-flex flex-column align-items-end" #right>
<div *ngFor="let val of item.right" class="box box-right">
{{val}}
</div>
</div>
</div>
<svg style="position: absolute; z-index: -1; width:100%; height:100%; top: 0; left: 0;">
<polyline *ngFor="let item of polylines"
[attr.points]="item.points"
[attr.fill]="item.fill"
[attr.stroke]="item.stroke"
[attr.stroke-width]="item.strokeWidth"
/>
</svg>
</div>
In app.component.css file:
.cont {
position: relative;
}
.box {
padding: 10px;
border: 1px solid #292929;
width: fit-content;
margin: 10px;
max-width: 200px;
}
.block {
margin: 10px;
}
In app.component.ts file:
import {
AfterViewInit,
Component,
ElementRef,
OnInit,
QueryList,
ViewChildren
} from "@angular/core";
export class Polyline {
points: string;
fill: string;
stroke: string;
strokeWidth: number;
constructor(
points?: string,
fill?: string,
stroke?: string,
strokeWidth?: number
) {
this.points = points || "";
this.fill = fill || "none";
this.stroke = stroke || "blue";
this.strokeWidth = strokeWidth || 3;
}
}
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit, AfterViewInit {
arr_item = [
{
left: ["Lorem Ipsum", "ABC"],
right: ["Hello World", "Hello"]
},
{
left: [
"Lorem Ipsum is simply dummy text of the printing and typesetting industry.",
"Lorem Ipsum is simply dummy text"
],
right: [""]
},
{
left: [
"",
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"
],
right: ["Rainbow"]
}
];
@ViewChildren("left", { read: ElementRef }) left: QueryList<ElementRef>;
@ViewChildren("right", { read: ElementRef }) right: QueryList<ElementRef>;
polylines: Polyline[] = [];
ngAfterViewInit() {
this.drawLines();
}
ngOnInit(): void {
window.addEventListener("resize", () => {
this.drawLines();
});
}
getPos_line(ele) {
var className = ele.getAttribute("class");
if (className.indexOf("left") !== -1) {
return {
x: Math.round(ele.offsetLeft + ele.offsetWidth),
y: Math.round(ele.offsetTop + ele.offsetHeight / 2)
};
} else {
return {
x: Math.round(ele.offsetLeft),
y: Math.round(ele.offsetTop + ele.offsetHeight / 2)
};
}
}
getMaxX_Left(arr: any) {
if (arr.length >= 1) {
var maxX = this.getPos_line(arr[0]).x;
for (var i = 0; i < arr.length; i++) {
var posLine = this.getPos_line(arr[i]);
if (posLine.x > maxX) {
maxX = posLine.x;
}
}
return maxX;
} else {
return null;
}
}
getMinX_Right(arr: any) {
if (arr.length >= 1) {
var minX = this.getPos_line(arr[0]).x;
for (var i = 0; i < arr.length; i++) {
var posLine = this.getPos_line(arr[i]);
if (posLine.x < minX) {
minX = posLine.x;
}
}
return minX;
} else {
return null;
}
}
getCenY(left, right) {
if (left.offsetHeight >= right.offsetHeight) {
return Math.round(left.offsetTop + left.offsetHeight / 2);
} else {
return Math.round(right.offsetTop + right.offsetHeight / 2);
}
}
drawLines() {
this.polylines = [];
for (var i = 0; i < this.arr_item.length; i++) {
var polylines_temp: Polyline[] = [];
var left_children = this.left.get(i).nativeElement.children;
var right_children = this.right.get(i).nativeElement.children;
var left_childrenLen = left_children.length;
var right_childrenLen = right_children.length;
var maxX_left = this.getMaxX_Left(left_children);
var minX_right = this.getMinX_Right(right_children);
var cenY = this.getCenY(
this.left.get(i).nativeElement,
this.right.get(i).nativeElement
);
var cenX = Math.round((maxX_left + minX_right) / 2);
var space = 0;
if (left_childrenLen > 1 && right_childrenLen > 1) {
space = 10;
}
for (var j = 0; j < left_childrenLen; j++) {
var posLine = this.getPos_line(left_children[j]);
polylines_temp.push(
new Polyline(`
${posLine.x},${posLine.y}
${cenX - space},${posLine.y}
${cenX - space},${cenY}
${cenX},${cenY}
`)
);
}
for (var j = 0; j < right_childrenLen; j++) {
var posLine = this.getPos_line(right_children[j]);
polylines_temp.push(
new Polyline(`
${cenX},${cenY}
${cenX + space},${cenY}
${cenX + space},${posLine.y}
${posLine.x},${posLine.y}
`)
);
}
this.polylines = this.polylines.concat(polylines_temp);
}
}
}
Link to Stackblitz
