From a5aac2da1d083194cbc1afb1427a0b39ee63a170 Mon Sep 17 00:00:00 2001 From: rubikscraft Date: Tue, 10 May 2022 11:12:15 +0200 Subject: [PATCH] made a working masonry component --- .../components/masonry/masonry.component.html | 4 +- .../components/masonry/masonry.component.scss | 11 ++ .../components/masonry/masonry.component.ts | 78 ++++++++-- .../app/routes/images/images.component.html | 33 +--- .../app/routes/images/images.component.scss | 2 +- .../src/app/routes/images/images.component.ts | 112 ++------------ .../src/app/services/api/image.service.ts | 21 ++- frontend/src/app/util/remove-children.ts | 5 + yarn.lock | 145 +++++++----------- 9 files changed, 177 insertions(+), 234 deletions(-) create mode 100644 frontend/src/app/util/remove-children.ts diff --git a/frontend/src/app/components/masonry/masonry.component.html b/frontend/src/app/components/masonry/masonry.component.html index 6dbc743..a6cb881 100644 --- a/frontend/src/app/components/masonry/masonry.component.html +++ b/frontend/src/app/components/masonry/masonry.component.html @@ -1 +1,3 @@ - + +
+
diff --git a/frontend/src/app/components/masonry/masonry.component.scss b/frontend/src/app/components/masonry/masonry.component.scss index e69de29..1c3c4e9 100644 --- a/frontend/src/app/components/masonry/masonry.component.scss +++ b/frontend/src/app/components/masonry/masonry.component.scss @@ -0,0 +1,11 @@ +:host { + display: flex; + flex-direction: row; +} + +.column { + display: flex; + flex-grow: 1; + flex-basis: 0; + flex-direction: column; +} diff --git a/frontend/src/app/components/masonry/masonry.component.ts b/frontend/src/app/components/masonry/masonry.component.ts index 97d3e90..953a1c4 100644 --- a/frontend/src/app/components/masonry/masonry.component.ts +++ b/frontend/src/app/components/masonry/masonry.component.ts @@ -3,13 +3,15 @@ import { Component, ContentChildren, ElementRef, - OnChanges, - OnInit, + Input, + OnDestroy, QueryList, - SimpleChanges, - ViewChild, + ViewChildren } from '@angular/core'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; +import { combineLatest, Subscription } from 'rxjs'; +import { RemoveChildren } from 'src/app/util/remove-children'; +import { Throttle } from 'src/app/util/throttle'; import { MasonryItemDirective } from './masonry-item.directive'; @Component({ @@ -17,9 +19,17 @@ import { MasonryItemDirective } from './masonry-item.directive'; templateUrl: './masonry.component.html', styleUrls: ['./masonry.component.scss'], }) -export class MasonryComponent implements AfterViewInit { +export class MasonryComponent implements AfterViewInit, OnDestroy { + @Input('columns') column_count: number = 1; + @Input('update-speed') update_speed: number = 200; + @ContentChildren(MasonryItemDirective) - content: QueryList; + private content: QueryList; + + @ViewChildren('column') + private columns: QueryList>; + + private sizesSubscription: Subscription | null = null; ngAfterViewInit(): void { this.subscribeContent(); @@ -27,8 +37,58 @@ export class MasonryComponent implements AfterViewInit { @AutoUnsubscribe() private subscribeContent() { - return this.content.changes.subscribe((items) => { - console.log('a', items.toArray()); - }); + return this.content.changes.subscribe( + (items: QueryList) => { + const sizes = items.map((i) => i.getSize()); + + if (this.sizesSubscription) { + this.sizesSubscription.unsubscribe(); + } + + this.sizesSubscription = combineLatest(sizes) + .pipe(Throttle(this.update_speed)) + .subscribe((output) => { + this.resortItems(items); + }); + + this.resortItems(items); + } + ); + } + + private resortItems(items: QueryList) { + const itemsArray = items.toArray(); + const columnsArray = this.columns.map((c) => c.nativeElement); + + for (let i = 0; i < columnsArray.length; i++) { + RemoveChildren(columnsArray[i]); + } + + const columnSizes = columnsArray.map((c) => 0); + + for (let i = 0; i < itemsArray.length; i++) { + const item = itemsArray[i]; + + let smallestColumn = 0; + let smallestColumnSize = columnSizes[0]; + for (let j = 1; j < columnSizes.length; j++) { + let better_j = (j + i) % columnSizes.length; + + if (columnSizes[better_j] <= smallestColumnSize) { + smallestColumn = better_j; + smallestColumnSize = columnSizes[better_j]; + } + } + + columnsArray[smallestColumn].appendChild(item.getElement()); + columnSizes[smallestColumn] += + item.getLastSize()?.contentRect.height ?? 0; + } + } + + ngOnDestroy() { + if (this.sizesSubscription) { + this.sizesSubscription.unsubscribe(); + } } } diff --git a/frontend/src/app/routes/images/images.component.html b/frontend/src/app/routes/images/images.component.html index 2daa283..6924587 100644 --- a/frontend/src/app/routes/images/images.component.html +++ b/frontend/src/app/routes/images/images.component.html @@ -1,5 +1,5 @@ - -
+ +
Image by you @@ -21,35 +21,6 @@
-
-
-
- - - Image by you - - Uploaded {{ image.created | amTimeAgo }} - - - - - - - - - -
-
-
-