From a874c7d70fec888b6ff55f7b8115ef60226f515e Mon Sep 17 00:00:00 2001 From: Braun Patrik Date: Sat, 25 Jun 2016 10:09:05 +0200 Subject: [PATCH] implementing advanced grid rendering (on scroll render more images) fixing slow image load --- .../gallery/grid/grid.gallery.component.ts | 81 +++++++++---------- .../photo/photo.grid.gallery.component.html | 2 +- .../photo/photo.grid.gallery.component.ts | 27 +++++-- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/frontend/app/gallery/grid/grid.gallery.component.ts b/frontend/app/gallery/grid/grid.gallery.component.ts index 6e3cb87e..32191a6b 100644 --- a/frontend/app/gallery/grid/grid.gallery.component.ts +++ b/frontend/app/gallery/grid/grid.gallery.component.ts @@ -8,7 +8,8 @@ import { ViewChild, ViewChildren, QueryList, - AfterViewInit + AfterViewInit, + HostListener } from "@angular/core"; import {Photo} from "../../../../common/entities/Photo"; import {GridRowBuilder} from "./GridRowBuilder"; @@ -41,56 +42,24 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit { } ngOnChanges() { - this.renderPhotos(); + this.onPhotosChanged(); } onResize() { - this.renderPhotos(); + this.onPhotosChanged(); } ngAfterViewInit() { this.lightbox.gridPhotoQL = this.gridPhotoQL; //TODO: implement scroll detection - /* this.gridPhotoQL.changes.subscribe( - (x)=> { - console.log("changed"); - if (!this.directory || this.gridPhotoQL.length < this.directory.photos.length) { - console.log("bad"); - console.log(this.directory ? this.gridPhotoQL.length + " < "+this.directory.photos.length : "no dir"); - return; - } - if (this.renderedContainerWidth != this.getContainerWidth()) { - this.renderPhotos(); - } - }, - (err) => { - console.log('Error: %s', err); - }, - () =>{ - console.log('Completed'); - } - - ); */ - setImmediate(() => { - this.renderPhotos(); - }); + this.onPhotosChanged(); } - private renderedContainerWidth = 0; - - private renderPhotos() { - if (this.getContainerWidth() == 0) { - return; - } - let maxRowHeight = window.innerHeight / this.MIN_ROW_COUNT; - let minRowHeight = window.innerHeight / this.MAX_ROW_COUNT; - let containerWidth = this.getContainerWidth(); - this.renderedContainerWidth = containerWidth; - + private onPhotosChanged() { this.photos.sort((a:Photo, b:Photo) => { if (a.metadata.creationDate > b.metadata.creationDate) { return 1; @@ -101,13 +70,28 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit { // a must be equal to b return 0; }); - this.photosToRender = []; - let i = 0; + this.renderedPhotoIndex = 0; + setImmediate(() => { + this.renderPhotos(); + }); + } - while (i < this.photos.length) { + private renderedPhotoIndex:number = 0; - let photoRowBuilder = new GridRowBuilder(this.photos, i, this.IMAGE_MARGIN, containerWidth); + private renderPhotos() { + if (this.getContainerWidth() == 0 || this.renderedPhotoIndex >= this.photos.length || !this.shouldRenderMore()) { + return; + } + + let maxRowHeight = window.innerHeight / this.MIN_ROW_COUNT; + let minRowHeight = window.innerHeight / this.MAX_ROW_COUNT; + + let renderedContentHeight = 0; + + while (this.renderedPhotoIndex < this.photos.length && this.shouldRenderMore(renderedContentHeight)) { + + let photoRowBuilder = new GridRowBuilder(this.photos, this.renderedPhotoIndex, this.IMAGE_MARGIN, this.getContainerWidth()); photoRowBuilder.addPhotos(this.TARGET_COL_COUNT); photoRowBuilder.adjustRowHeightBetween(minRowHeight, maxRowHeight); @@ -119,11 +103,24 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit { this.photosToRender.push(new GridPhoto(photo, imageWidth, imageHeight)); }); - i += photoRowBuilder.getPhotoRow().length; + renderedContentHeight += rowHeight; + this.renderedPhotoIndex += photoRowBuilder.getPhotoRow().length; + } } + private shouldRenderMore(offset:number = 0):boolean { + return document.body.scrollTop >= (document.body.clientHeight + offset - window.innerHeight) * 0.7 + || document.body.clientHeight + offset < window.innerHeight; + + } + + @HostListener('window:scroll') + onScroll() { + this.renderPhotos(); + } + private getContainerWidth():number { if (!this.gridContainer) { return 0; diff --git a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.html b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.html index 58c88ad3..60361ab8 100644 --- a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.html +++ b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.html @@ -1,5 +1,5 @@
- + diff --git a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts index 859505e7..b0ec1e9d 100644 --- a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts +++ b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts @@ -1,6 +1,6 @@ /// -import {Component, Input, ElementRef, ViewChild, OnInit, AfterViewInit, OnDestroy, HostListener} from "@angular/core"; +import {Component, Input, ElementRef, ViewChild, OnInit, AfterViewInit, OnDestroy, Renderer} from "@angular/core"; import {IRenderable, Dimension} from "../../../model/IRenderable"; import {GridPhoto} from "../GridPhoto"; import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem"; @@ -34,7 +34,7 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit loading = { animate: false, - show: false + show: true }; thumbnailTask:ThumbnailTaskEntity = null; @@ -47,9 +47,13 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit SearchTypes:any = []; searchEnabled:boolean = true; - constructor(private thumbnailService:ThumbnailLoaderService) { + scrollListener = null; + + constructor(private thumbnailService:ThumbnailLoaderService, private renderer:Renderer) { this.SearchTypes = SearchTypes; this.searchEnabled = Config.Client.Search.searchEnabled; + + } ngOnInit() { @@ -57,7 +61,7 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit if (this.gridPhoto.isThumbnailAvailable()) { this.image.src = this.gridPhoto.getThumbnailPath(); this.image.show = true; - this.loading.show = false; + // this.loading.show = false; } else { if (this.gridPhoto.isReplacementThumbnailAvailable()) { @@ -84,15 +88,23 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit this.image.show = true; this.loading.show = false; this.thumbnailTask = null; + if (this.scrollListener) { + this.scrollListener(); + } }, onError: (error)=> {//onError this.thumbnailTask = null; + if (this.scrollListener) { + this.scrollListener(); + } //TODO: handle error console.error("something bad happened"); console.error(error); } }; - + this.scrollListener = this.renderer.listenGlobal('window', 'scroll', () => { + this.onScroll(); + }); if (this.gridPhoto.isReplacementThumbnailAvailable()) { this.thumbnailTask = this.thumbnailService.loadImage(this.gridPhoto, ThumbnailLoadingPriority.medium, listener); } else { @@ -117,7 +129,6 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit && document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop; } - @HostListener('window:scroll') onScroll() { if (this.thumbnailTask != null) { if (this.isInView() == true) { @@ -157,6 +168,10 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit } + onImageLoad() { + this.loading.show = false; + } + public getDimension():Dimension { return new Dimension(this.imageRef.nativeElement.offsetTop, this.imageRef.nativeElement.offsetLeft,