Reputation: 45
When I used the custom masonry package implement on the angular with help of custome directive then first time content overlapped, I did not calculate proper position Why did this happen?
I check debug then targetindex not proper someTime that's why they overlap with above content so What can i do?
I think the issue happened only in the directive.
import { Directive, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, Renderer2 } from '@angular/core';
import $ from 'jquery';
@Directive({
selector: '[appPinGrid]',
// standalone: true
})
export class PinGridDirective implements OnChanges, OnDestroy {
@Input()
gutter: number = 0;
@Input()
columns: number = 0;
@Input()
minColWidth: number = 2;
@Input()
maxColWidth: number = 10;
@Input()
doubleColumnWidth: number = 10;
@Input()
itemClass: string = '';
@Input() public data: any;
@Output() onLayoutComplete: EventEmitter<any> = new EventEmitter();
container: any;
containerWidth: number = 0;
containeHeight: number = 0;
columnWidth: any;
items: any;
// columns of grid
columnHeightArray: any;
// timer for detect changes
controlSkipper: any;
resizeControlSkipper: any;
// host listener for resize window
// resizeListener: any;
isSearchFirstTime: any = true;
constructor(public el: ElementRef, public renderer: Renderer2) { }
ngOnDestroy() {
// unsubscribe event listener
this.resizeListener();
}
resizeListener(){
this.renderer.listen('window', 'resize', () => {
if (this.resizeControlSkipper)
clearTimeout(this.controlSkipper)
this.resizeControlSkipper = setTimeout(() => {
// console.log('relayout call');
this.reLayout();
}, 400);
});
}
ngOnChanges(changes: { data: any; }) {
if (this.isSearchFirstTime) {
this.isSearchFirstTime = false;
// this is for skip first changes detect for initialieze all directive (scroll unnecessary api of second page from here so this solution is apply)
} else {
if (changes.data) {
if (this.controlSkipper)
clearTimeout(this.controlSkipper)
this.controlSkipper = setTimeout(async () => {
this.reLayout();
}, 500);
}
}
}
reLayout() {
// console.log('relayout');
this.container = this.el.nativeElement;
this.items = this.el.nativeElement.childNodes;
this.items.forEach((element: any) => {
$(element).css('opacity', '0');
});
this.layoutItem();
}
async layoutItem() {
// console.log('layout');
this.getColumnWidth();
this.initColumnHeightarray();
for (var i = 0; i < this.items.length; i++) {
this.placeItem(this.items[i]);
}
this.items.forEach((element: any) => {
console.log('element: ', element);
$(element).css('opacity', '1');
});
console.log('layout complete in function');
await $(this.container).height(Math.max.apply({}, this.columnHeightArray));
// console.log('set wrapper height', Math.max.apply({}, this.columnHeightArray));
await this.onLayoutComplete.emit('LayoutComplete');
}
initColumnHeightarray() {
this.resetColumnHeight();
for (var i = 0; i < this.columns; i++) {
this.columnHeightArray.push(0);
}
}
resetColumnHeight() {
this.columnHeightArray = [];
}
getColumnWidth() {
this.containerWidth = this.el.nativeElement.offsetWidth;
this.columnWidth = Math.floor((this.containerWidth / this.columns) - this.gutter);
if (this.columnWidth <= Number(this.minColWidth) && this.columns >= 2) {
this.columns--;
this.getColumnWidth();
}
// in below condition I check double column width
// because column minus if card width < 200 and suppose column = 1 then it's width is increase
// now maximum card width is 300 and container is about 465(200 column width + 2 number of column + 2 * gutter size) something, so that, below condition is become true and add one column i.e. 2.
// now two column card width is again < 200 thus it will gose to infonite.
// so I check that if container have enough space to display two column then I add column othersize it will display only one column
if (this.columnWidth >= Number(this.maxColWidth) && this.containerWidth > this.doubleColumnWidth) {
this.columns++;
this.getColumnWidth();
}
}
calculateImageSize() {
}
async placeItem(item: { nodeType: number; getElementsByClassName: (arg0: string) => { (): any; new(): any; length: number; }; }) {
if (item.nodeType != Node.ELEMENT_NODE) {
return; // Skip non-element nodes
}
// Find the column with the minimum height
const minimumColHeight = Math.min.apply({}, this.columnHeightArray);
const minColIndex = $.inArray(minimumColHeight, this.columnHeightArray);
// Calculate the position
const targetIndex = minColIndex;
const fixMarginLeft = (this.containerWidth - this.columnWidth * this.columns - this.gutter * (this.columns - 1)) / 2;
// If the item has the specified class, adjust its size
if (item.getElementsByClassName(this.itemClass).length > 0) {
const img = item.getElementsByClassName(this.itemClass)[0];
$(img).css('position', 'initial');
// Ensure width and height are correctly set for proper placement
const aspectRatio = $(img).width() / ($(img).height() || 1);
$(img).css('width', this.columnWidth);
$(img).css('height', Math.floor(this.columnWidth / aspectRatio));
}
// Calculate the position for the item
console.log('this.columnHeightArray[targetIndex]: ', this.columnHeightArray[targetIndex]);
const position = {
left: (this.columnWidth + this.gutter) * targetIndex + fixMarginLeft,
top: this.columnHeightArray[targetIndex] + this.gutter // Adding gutter to the top position
};
// Position the item
$(item).css('position', 'absolute');
$(item).css('top', position.top);
$(item).css('left', position.left);
// Update the column height to account for the new item
this.columnHeightArray[targetIndex] += $(item).outerHeight() + this.gutter; // Update column height including gutter
console.log('this.columnHeightArray[targetIndex]: ', this.columnHeightArray[targetIndex]);
}
}
I want to do proper adjust position how can i do?
Upvotes: 0
Views: 28