1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

removing animation from lightbox + improving thumbnail rendering at lightbox

This commit is contained in:
Braun Patrik 2016-07-04 16:58:10 +02:00
parent 83d1d52813
commit 8e14c613ea
9 changed files with 109 additions and 170 deletions

View File

@ -1,8 +1,10 @@
<gallery-lightbox #lightbox></gallery-lightbox>
<gallery-lightbox #lightbox (onLastElement)="onLightboxLastElement()"></gallery-lightbox>
<app-frame>
<div navbar>
<gallery-search #search *ngIf="showSearchBar"></gallery-search>
</div>
<div body class="container" style="width: 100%; padding:0" *ngIf="_galleryService.content.directory">
<gallery-navbar [directory]="_galleryService.content.directory"></gallery-navbar>
<gallery-directory *ngFor="let directory of _galleryService.content.directory.directories"

View File

@ -27,6 +27,7 @@ import {GalleryNavigatorComponent} from "./navigator/navigator.gallery.component
export class GalleryComponent implements OnInit {
@ViewChild(GallerySearchComponent) search:GallerySearchComponent;
@ViewChild(GalleryGridComponent) grid:GalleryGridComponent;
public showSearchBar:boolean = true;
@ -70,6 +71,10 @@ export class GalleryComponent implements OnInit {
}
onLightboxLastElement() {
this.grid.renderARow();
}
}

View File

@ -1,4 +1,4 @@
import {it, inject, beforeEachProviders} from "@angular/core/testing";
import {it, inject, addProviders} from "@angular/core/testing";
import {BaseRequestOptions, Http} from "@angular/http";
import {MockBackend} from "@angular/http/testing";
import {provide} from "@angular/core";
@ -9,18 +9,20 @@ import {GalleryService} from "./gallery.service";
describe('GalleryService', () => {
beforeEach(() => {
addProviders([
MockBackend,
BaseRequestOptions,
provide(Http, {
useFactory: (backend, options) => {
return new Http(backend, options);
}, deps: [MockBackend, BaseRequestOptions]
}),
NetworkService,
GalleryService
]);
});
beforeEachProviders(() => [
MockBackend,
BaseRequestOptions,
provide(Http, {
useFactory: (backend, options) => {
return new Http(backend, options);
}, deps: [MockBackend, BaseRequestOptions]
}),
NetworkService,
GalleryService
]);
it('placeholder test', inject([], () => {

View File

@ -33,6 +33,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
@Input() lightbox:GalleryLightboxComponent;
photosToRender:Array<GridPhoto> = [];
containerWidth:number = 0;
private IMAGE_MARGIN = 2;
private TARGET_COL_COUNT = 5;
@ -58,6 +59,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
if (this.isAfterViewInit === false) {
return;
}
this.updateContainerWidth();
this.sortPhotos();
this.clearRenderedPhotos();
setImmediate(() => {
@ -73,7 +75,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
//TODO: implement scroll detection
this.sortPhotos();
this.updateContainerWidth();
this.clearRenderedPhotos();
setImmediate(() => {
this.renderPhotos();
@ -130,31 +132,15 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
private renderedPhotoIndex:number = 0;
private renderPhotos() {
if (this.getContainerWidth() == 0 || this.renderedPhotoIndex >= this.photos.length || !this.shouldRenderMore()) {
if (this.containerWidth == 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) === true) {
let photoRowBuilder = new GridRowBuilder(this.photos, this.renderedPhotoIndex, this.IMAGE_MARGIN, this.getContainerWidth());
photoRowBuilder.addPhotos(this.TARGET_COL_COUNT);
photoRowBuilder.adjustRowHeightBetween(minRowHeight, maxRowHeight);
let rowHeight = photoRowBuilder.calcRowHeight();
let imageHeight = rowHeight - (this.IMAGE_MARGIN * 2);
photoRowBuilder.getPhotoRow().forEach((photo) => {
let imageWidth = imageHeight * (photo.metadata.size.width / photo.metadata.size.height);
this.photosToRender.push(new GridPhoto(photo, imageWidth, imageHeight, this.renderedPhotoIndex));
});
renderedContentHeight += rowHeight;
this.renderedPhotoIndex += photoRowBuilder.getPhotoRow().length;
renderedContentHeight += this.renderARow();
}
}
@ -184,11 +170,33 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
}
}
private getContainerWidth():number {
public renderARow():number {
let maxRowHeight = window.innerHeight / this.MIN_ROW_COUNT;
let minRowHeight = window.innerHeight / this.MAX_ROW_COUNT;
let photoRowBuilder = new GridRowBuilder(this.photos, this.renderedPhotoIndex, this.IMAGE_MARGIN, this.containerWidth);
photoRowBuilder.addPhotos(this.TARGET_COL_COUNT);
photoRowBuilder.adjustRowHeightBetween(minRowHeight, maxRowHeight);
let rowHeight = photoRowBuilder.calcRowHeight();
let imageHeight = rowHeight - (this.IMAGE_MARGIN * 2);
photoRowBuilder.getPhotoRow().forEach((photo) => {
let imageWidth = imageHeight * (photo.metadata.size.width / photo.metadata.size.height);
this.photosToRender.push(new GridPhoto(photo, imageWidth, imageHeight, this.renderedPhotoIndex));
});
this.renderedPhotoIndex += photoRowBuilder.getPhotoRow().length;
console.log(this.photosToRender.length);
return rowHeight;
}
private updateContainerWidth():number {
if (!this.gridContainer) {
return 0;
return;
}
return this.gridContainer.nativeElement.clientWidth;
this.containerWidth = this.gridContainer.nativeElement.clientWidth;
}

View File

@ -3,16 +3,16 @@
z-index: 1100; /* Sit on top */
left: 0;
top: 0;
width: 0; /* Full width */
height: 0; /* Full height */
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: hidden;
display: flex; /* add */
justify-content: center; /* add to align horizontal */
align-items: center; /* add to align vertical */
cursor: pointer;
}
.blackCanvas{
display: none;
position: fixed; /* Stay in place */
z-index: 1099; /* Sit on top */
left: 0;

View File

@ -1,10 +1,14 @@
<div [hidden]="!activePhoto">
<div class="blackCanvas" #blackCanvas>
<div class="blackCanvas">
</div>
<div class="lightbox" #lightbox>
<gallery-lightbox-photo #imgContainer [gridPhoto]="activePhoto ? activePhoto.gridPhoto : null">
<div class="lightbox">
<gallery-lightbox-photo [gridPhoto]="activePhoto ? activePhoto.gridPhoto : null"
[style.top.px]="photoDimension.top"
[style.left.px]="photoDimension.left"
[style.width.px]="photoDimension.width"
[style.height.px]="photoDimension.height">
</gallery-lightbox-photo>
</div>

View File

@ -1,6 +1,6 @@
///<reference path="../../../browser.d.ts"/>
import {Component, ElementRef, ViewChild, QueryList} from "@angular/core";
import {Component, QueryList, Output, EventEmitter} from "@angular/core";
import {Photo} from "../../../../common/entities/Photo";
import {GalleryPhotoComponent} from "../grid/photo/photo.grid.gallery.component.ts";
import {BrowserDomAdapter} from "@angular/platform-browser/src/browser/browser_adapter";
@ -14,15 +14,11 @@ import {GalleryLightboxPhotoComponent} from "./photo/photo.lightbox.gallery.comp
directives: [GalleryLightboxPhotoComponent]
})
export class GalleryLightboxComponent {
@Output('onLastElement') onLastElement = new EventEmitter();
@ViewChild('lightbox') lightBoxDiv:ElementRef;
@ViewChild('blackCanvas') blackCanvasDiv:ElementRef;
@ViewChild('controls') controlsDiv:ElementRef;
@ViewChild('imgContainer') imgContainer:GalleryLightboxPhotoComponent;
public imageSize = {width: "auto", height: "100"};
public navigation = {hasPrev: true, hasNext: true};
public photoDimension:Dimension = new Dimension(0, 0, 0, 0);
private activePhoto:GalleryPhotoComponent;
public gridPhotoQL:QueryList<GalleryPhotoComponent>;
@ -42,20 +38,16 @@ export class GalleryLightboxComponent {
if (pcList[i] === this.activePhoto && i + 1 < pcList.length) {
this.activePhoto = pcList[i + 1];
this.navigation.hasPrev = true;
if (i + 2 < pcList.length) {
this.navigation.hasNext = true;
} else {
this.navigation.hasNext = false;
this.navigation.hasNext = i + 2 < pcList.length;
if (i + 3 === pcList.length) {
this.onLastElement.emit({}); //trigger to render more photos if there are
}
let toImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
this.forceAnimateFrom(toImage,
{},
this.imgContainer.nativeElement.nativeElement);
this.photoDimension = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo);
this.setImageSize();
return;
}
}
@ -67,33 +59,16 @@ export class GalleryLightboxComponent {
if (pcList[i] === this.activePhoto && i > 0) {
this.activePhoto = pcList[i - 1];
this.navigation.hasNext = true;
if (i - 1 > 0) {
this.navigation.hasPrev = true;
} else {
this.navigation.hasPrev = false;
}
this.navigation.hasPrev = i - 1 > 0;
let toImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
this.photoDimension = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo);
this.forceAnimateFrom(toImage,
{},
this.imgContainer.nativeElement.nativeElement);
this.setImageSize();
return;
}
}
}
private setImageSize() {
if (this.activePhoto.gridPhoto.photo.metadata.size.height > this.activePhoto.gridPhoto.photo.metadata.size.width) {
this.imageSize.height = "100";
this.imageSize.width = null;
} else {
this.imageSize.height = null;
this.imageSize.width = "100";
}
}
public show(photo:Photo) {
let selectedPhoto = this.findPhotoComponent(photo);
@ -103,73 +78,20 @@ export class GalleryLightboxComponent {
this.dom.setStyle(this.dom.query('body'), 'overflow', 'hidden');
this.activePhoto = selectedPhoto;
this.setImageSize();
let from = this.activePhoto.getDimension();
from.top -= this.getBodyScrollTop();
let fromImage = {width: from.width + "px", height: from.height + "px", top: "0px", left: "0px"};
let toImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
this.forceAnimateFrom(fromImage,
toImage,
this.imgContainer.nativeElement.nativeElement);
this.forceAnimateFrom(from.toStyle(),
{height: "100%", width: "100%", "top": "0px", "left": "0px"},
this.lightBoxDiv.nativeElement);
this.forceAnimateFrom({opacity: "0", display: "block"},
{opacity: "1"},
this.blackCanvasDiv.nativeElement);
this.forceAnimateFrom({opacity: "0", display: "block"},
{opacity: "1"},
this.controlsDiv.nativeElement);
this.photoDimension = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo);
}
public hide() {
console.log("hiding");
let to = this.activePhoto.getDimension();
//iff target image out of screen -> scroll to there
if (this.getBodyScrollTop() > to.top || this.getBodyScrollTop() + this.getScreenHeight() < to.top) {
this.setBodyScrollTop(to.top);
}
to.top -= this.getBodyScrollTop();
this.forceAnimateTo({height: "100%", width: "100%", "top": "0px", "left": "0px"},
to.toStyle(),
this.lightBoxDiv.nativeElement,
{height: "0px", width: "0px", "top": "0px", "left": "0px"},
()=> {
this.activePhoto = null;
});
this.dom.setStyle(this.dom.query('body'), 'overflow', 'auto');
this.forceAnimateTo({opacity: "1.0", display: "block"},
{opacity: "0.0", display: "block"},
this.blackCanvasDiv.nativeElement,
{display: "none"});
this.forceAnimateTo({opacity: "1.0", display: "block"},
{opacity: "0.0", display: "block"},
this.controlsDiv.nativeElement,
{display: "none"});
let fromImage = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo).toStyle();
let toImage = {width: to.width + "px", height: to.height + "px", top: "0px", left: "0px"};
this.forceAnimateTo(fromImage,
toImage,
this.imgContainer.nativeElement.nativeElement);
this.activePhoto = null;
}
@ -186,39 +108,6 @@ export class GalleryLightboxComponent {
return selectedPhoto;
}
private forceAnimateFrom(from, to, elemnet) {
/* let anim0 = this.animBuilder.css();
anim0.setDuration(0);
anim0.setToStyles(from);
anim0.start(elemnet).onComplete(()=> {
let anim1 = this.animBuilder.css();
anim1.setDuration(500);
anim1.setFromStyles(from);
anim1.setToStyles(to);
anim1.start(elemnet);
});*/
}
private forceAnimateTo(from, to, elemnet, innerTo = null, onComplete = ()=> {
}) {
/* if (innerTo == null) {
innerTo = to;
}
let anim0 = this.animBuilder.css();
anim0.setDuration(500);
anim0.setFromStyles(from);
anim0.setToStyles(to);
anim0.start(elemnet).onComplete(()=> {
let anim1 = this.animBuilder.css();
anim1.setDuration(0);
anim1.setToStyles(innerTo);
anim1.start(elemnet).onComplete(onComplete);
});*/
onComplete();
}
private getBodyScrollTop() {
return this.dom.getProperty(this.dom.query('body'), 'scrollTop');

View File

@ -1,13 +1,15 @@
<div class="imgContainer" #imgContainer>
<img *ngIf="gridPhoto"
<img *ngIf="showThumbnail()"
[style.width.%]="imageSize.width"
[style.height.%]="imageSize.height"
[src]="gridPhoto.getThumbnailPath()"/>
[src]="thumbnailPath()"/>
<img *ngIf="gridPhoto"
[style.width.%]="imageSize.width"
[style.height.%]="imageSize.height"
[src]="gridPhoto.getPhotoPath()"/>
[src]="gridPhoto.getPhotoPath()"
(load)="onImageLoad()"
(error)="onImageError()"/>
</div>

View File

@ -15,11 +15,14 @@ export class GalleryLightboxPhotoComponent implements OnChanges {
public imageSize = {width: "auto", height: "100"};
@ViewChild('imgContainer') nativeElement:ElementRef;
imageLoaded:boolean = false;
constructor() {
}
ngOnChanges() {
this.imageLoaded = false;
this.setImageSize();
}
@ -37,5 +40,29 @@ export class GalleryLightboxPhotoComponent implements OnChanges {
}
}
onImageLoad() {
this.imageLoaded = true;
}
onImageError() {
//TODO:handle error
console.error("cant load image");
}
public showThumbnail():boolean {
return this.gridPhoto && !this.imageLoaded &&
(this.gridPhoto.isThumbnailAvailable() || this.gridPhoto.isReplacementThumbnailAvailable());
}
public thumbnailPath():string {
if (this.gridPhoto.isThumbnailAvailable() === true)
return this.gridPhoto.getThumbnailPath();
if (this.gridPhoto.isReplacementThumbnailAvailable() === true)
return this.gridPhoto.getReplacementThumbnailPath();
return null
}
}