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

implementing lightbox image zoom

This commit is contained in:
Patrik J. Braun 2018-12-18 00:06:25 +01:00
parent ada2c007df
commit 531759f54b
7 changed files with 166 additions and 13 deletions

View File

@ -80,11 +80,16 @@ import {FileSizePipe} from './pipes/FileSizePipe';
@Injectable() @Injectable()
export class MyHammerConfig extends HammerGestureConfig { export class MyHammerConfig extends HammerGestureConfig {
overrides = <any>{ events: string[] = ['pinch'];
'swipe': {direction: 31} // enable swipe up overrides = {
pan: {threshold: 1},
swipe: {direction: 31}, // enable swipe up
pinch: {enable: true}
}; };
} }
export class CustomUrlSerializer implements UrlSerializer { export class CustomUrlSerializer implements UrlSerializer {
private _defaultUrlSerializer: DefaultUrlSerializer = new DefaultUrlSerializer(); private _defaultUrlSerializer: DefaultUrlSerializer = new DefaultUrlSerializer();

View File

@ -10,7 +10,6 @@ import {Config} from '../../../common/config/public/Config';
import {ShareService} from './share.service'; import {ShareService} from './share.service';
import {NavigationService} from '../model/navigation.service'; import {NavigationService} from '../model/navigation.service';
import {SortingMethods} from '../../../common/entities/SortingMethods'; import {SortingMethods} from '../../../common/entities/SortingMethods';
import {QueryService} from '../model/query.service';
import {QueryParams} from '../../../common/QueryParams'; import {QueryParams} from '../../../common/QueryParams';

View File

@ -52,7 +52,7 @@
: {{VideoData.duration | duration}}</div> : {{VideoData.duration | duration}}</div>
<div class="col-6" *ngIf="VideoData.bitRate"> <div class="col-6" *ngIf="VideoData.bitRate">
<ng-container i18n>bit rate</ng-container> <ng-container i18n>bit rate</ng-container>
: {{calcSize(VideoData.bitRate)}}/s : {{VideoData.bitRate | fileSize}}/s
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,6 +7,8 @@
<div class="lightbox" #lightbox> <div class="lightbox" #lightbox>
<app-gallery-lightbox-media [gridMedia]="activePhoto ? activePhoto.gridPhoto : null" <app-gallery-lightbox-media [gridMedia]="activePhoto ? activePhoto.gridPhoto : null"
[loadMedia]="!animating" [loadMedia]="!animating"
[zoom]="zoom"
[drag]="drag"
[windowAspect]="getWindowAspectRatio()" [windowAspect]="getWindowAspectRatio()"
#photo> #photo>
</app-gallery-lightbox-media> </app-gallery-lightbox-media>
@ -58,18 +60,18 @@
</div> </div>
</div> </div>
<div id="swipeable-container" <div id="swipeable-container"
(swipeleft)="nextImage()" (swipeleft)="zoom == 1 && nextImage()"
(swiperight)="prevImage()" (swiperight)="zoom == 1 && prevImage()"
(swipeup)="hide()" (swipeup)="zoom == 1 && hide()"
(click)="photo.playPause()"> (click)="photo.playPause()">
<div class="navigation-arrow highlight" <div class="navigation-arrow highlight"
*ngIf="navigation.hasPrev" title="key: left arrow" id="leftArrow" i18n-title *ngIf="navigation.hasPrev && zoom == 1" title="key: left arrow" id="leftArrow" i18n-title
(click)="prevImage()"><span (click)="prevImage()"><span
class="oi oi-chevron-left"></span></div> class="oi oi-chevron-left"></span></div>
<div class="navigation-arrow highlight" <div class="navigation-arrow highlight"
*ngIf="navigation.hasNext" title="key: right arrow" id="rightArrow" i18n-title *ngIf="navigation.hasNext && zoom == 1" title="key: right arrow" id="rightArrow" i18n-title
(click)="nextImage()"><span (click)="nextImage()"><span
class="oi oi-chevron-right"></span></div> class="oi oi-chevron-right"></span></div>

View File

@ -23,6 +23,8 @@ import {MediaDTO} from '../../../../common/entities/MediaDTO';
import {QueryParams} from '../../../../common/QueryParams'; import {QueryParams} from '../../../../common/QueryParams';
import {GalleryService} from '../gallery.service'; import {GalleryService} from '../gallery.service';
import {PhotoDTO} from '../../../../common/entities/PhotoDTO'; import {PhotoDTO} from '../../../../common/entities/PhotoDTO';
import {$e} from '@angular/compiler/src/chars';
import {Utils} from '../../../../common/Utils';
export enum LightboxStates { export enum LightboxStates {
Open = 1, Open = 1,
@ -70,7 +72,10 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
iPvisibilityTimer: number = null; iPvisibilityTimer: number = null;
visibilityTimer: number = null; visibilityTimer: number = null;
delayedMediaShow: string = null; delayedMediaShow: string = null;
public zoom = 1;
public drag = {x: 0, y: 0};
private prevDrag = {x: 0, y: 0};
private prevZoom = 1;
constructor(public fullScreenService: FullScreenService, constructor(public fullScreenService: FullScreenService,
private changeDetector: ChangeDetectorRef, private changeDetector: ChangeDetectorRef,
@ -119,6 +124,8 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
if (this.activePhoto && this.queryService.getMediaStringId(this.activePhoto.gridPhoto.media) === photoStringId) { if (this.activePhoto && this.queryService.getMediaStringId(this.activePhoto.gridPhoto.media) === photoStringId) {
return; return;
} }
this.setZoom(1);
const photo = this.gridPhotoQL.find(i => this.queryService.getMediaStringId(i.gridPhoto.media) === photoStringId); const photo = this.gridPhotoQL.find(i => this.queryService.getMediaStringId(i.gridPhoto.media) === photoStringId);
if (!photo) { if (!photo) {
return this.delayedMediaShow = photoStringId; return this.delayedMediaShow = photoStringId;
@ -150,6 +157,128 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
} }
} }
@HostListener('pan', ['$event'])
dragging($event: any) {
if (this.zoom === 1) {
return;
}
this.drag.x = this.prevDrag.x + $event.deltaX;
this.drag.y = this.prevDrag.y + $event.deltaY;
this.checkZoomAndDrag();
if ($event.isFinal) {
this.prevDrag = {
x: this.drag.x,
y: this.drag.y,
};
}
}
@HostListener('window:wheel', ['$event'])
onWheel($event: any) {
this.setZoom(this.zoom + ($event.deltaY < 0 ? this.zoom / 10 : -this.zoom / 10));
}
@HostListener('pinch', ['$event'])
pinch($event: any) {
this.setZoom(this.prevZoom * $event.scale);
}
@HostListener('pinchend', ['$event'])
pinchend($event: any) {
this.setZoom(this.prevZoom * $event.scale);
this.prevZoom = this.zoom;
}
@HostListener('tap', ['$event'])
tao($event: any) {
if ($event.tapCount < 2) {
return;
}
if (this.zoom > 1) {
this.setZoom(1);
this.prevZoom = this.zoom;
return;
} else {
this.setZoom(5);
this.prevZoom = this.zoom;
return;
}
}
private setZoom(zoom: number) {
if (!this.activePhoto || this.activePhoto.gridPhoto.isVideo()) {
return;
}
if (zoom < 1) {
zoom = 1;
}
if (zoom > 10) {
zoom = 10;
}
this.drag.x = this.drag.x / this.zoom * zoom;
this.drag.y = this.drag.y / this.zoom * zoom;
this.prevDrag.x = this.drag.x;
this.prevDrag.y = this.drag.y;
this.zoom = zoom;
this.checkZoomAndDrag();
}
private checkZoomAndDrag() {
const fixDrag = (drag: { x: number, y: number }) => {
if (this.zoom === 1) {
drag.y = 0;
drag.x = 0;
return;
}
if (!this.activePhoto) {
return;
}
const photoAspect = MediaDTO.calcRotatedAspectRatio(this.activePhoto.gridPhoto.media);
const widthFilled = photoAspect > this.getWindowAspectRatio();
const divWidth = this.getPhotoFrameWidth();
const divHeight = this.getPhotoFrameHeight();
const size = {
width: (widthFilled ? divWidth : divHeight * photoAspect) * this.zoom,
height: (widthFilled ? divWidth / photoAspect : divHeight) * this.zoom
};
const widthDrag = Math.abs(divWidth - size.width) / 2;
const heightDrag = Math.abs(divHeight - size.height) / 2;
if (divWidth > size.width) {
drag.x = 0;
}
if (divHeight > size.height) {
drag.y = 0;
}
if (drag.x < -widthDrag) {
drag.x = -widthDrag;
}
if (drag.x > widthDrag) {
drag.x = widthDrag;
}
if (drag.y < -heightDrag) {
drag.y = -heightDrag;
}
if (drag.y > heightDrag) {
drag.y = heightDrag;
}
};
if (this.zoom < 1) {
this.zoom = 1;
}
if (this.zoom > 10) {
this.zoom = 10;
}
fixDrag(this.drag);
fixDrag(this.prevDrag);
}
//noinspection JSUnusedGlobalSymbols //noinspection JSUnusedGlobalSymbols
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize() { onResize() {
@ -185,6 +314,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
} }
public showLigthbox(photo: MediaDTO) { public showLigthbox(photo: MediaDTO) {
this.setZoom(1);
this.controllersVisible = true; this.controllersVisible = true;
this.showControls(); this.showControls();
this.status = LightboxStates.Open; this.status = LightboxStates.Open;
@ -275,6 +405,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
} }
private hideLigthbox() { private hideLigthbox() {
this.setZoom(1);
this.controllersVisible = false; this.controllersVisible = false;
this.status = LightboxStates.Closing; this.status = LightboxStates.Closing;
this.fullScreenService.exitFullScreen(); this.fullScreenService.exitFullScreen();
@ -347,6 +478,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
this.iPvisibilityTimer = window.setTimeout(() => { this.iPvisibilityTimer = window.setTimeout(() => {
this.iPvisibilityTimer = null; this.iPvisibilityTimer = null;
this.infoPanelVisible = false; this.infoPanelVisible = false;
this.checkZoomAndDrag();
}, 1000); }, 1000);
const starPhotoPos = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.media); const starPhotoPos = this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.media);
@ -417,6 +549,8 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
if (this.iPvisibilityTimer != null) { if (this.iPvisibilityTimer != null) {
clearTimeout(this.iPvisibilityTimer); clearTimeout(this.iPvisibilityTimer);
} }
this.checkZoomAndDrag();
} }
public fastForward() { public fastForward() {

View File

@ -2,23 +2,26 @@
<img *ngIf="showThumbnail()" <img *ngIf="showThumbnail()"
[style.width.%]="imageSize.width" [style.width.%]="imageSize.width"
[style.height.%]="imageSize.height" [style.height.%]="imageSize.height"
[style.transform]="ImageTransform"
[src]="thumbnailSrc"/> [src]="thumbnailSrc"/>
<img *ngIf="gridMedia !== null && gridMedia.isPhoto() && loadMedia && photoSrc" <img *ngIf="gridMedia !== null && gridMedia.isPhoto() && loadMedia && photoSrc"
[style.width.%]="imageSize.width" [style.width.%]="imageSize.width"
[style.height.%]="imageSize.height" [style.height.%]="imageSize.height"
[style.transform]="ImageTransform"
[src]="photoSrc" [src]="photoSrc"
[alt]="gridMedia.media.name"
(load)="onImageLoad()" (load)="onImageLoad()"
(error)="onImageError()"/> (error)="onImageError()"/>
<video #video <video #video
*ngIf="gridMedia !== null && gridMedia.isVideo() && loadMedia" *ngIf="gridMedia !== null && gridMedia.isVideo() && loadMedia"
[style.width.%]="imageSize.width" [style.width.%]="imageSize.width"
[style.height.%]="imageSize.height" [style.height.%]="imageSize.height"
(loadstart)="onImageLoad()" (loadstart)="onImageLoad()"
autoplay autoplay
(error)="onImageError()" (error)="onImageError()"
(timeupdate)="onVideoProgress()" > (timeupdate)="onVideoProgress()">
<source [src]="gridMedia.getPhotoPath()" type="{{getVideoType()}}"> <source [src]="gridMedia.getPhotoPath()" type="{{getVideoType()}}">
</video> </video>

View File

@ -2,6 +2,7 @@ import {Component, ElementRef, Input, Output, OnChanges, ViewChild} from '@angul
import {GridMedia} from '../../grid/GridMedia'; import {GridMedia} from '../../grid/GridMedia';
import {FixOrientationPipe} from '../../FixOrientationPipe'; import {FixOrientationPipe} from '../../FixOrientationPipe';
import {MediaDTO} from '../../../../../common/entities/MediaDTO'; import {MediaDTO} from '../../../../../common/entities/MediaDTO';
import {DomSanitizer, SafeStyle} from '@angular/platform-browser';
@Component({ @Component({
selector: 'app-gallery-lightbox-media', selector: 'app-gallery-lightbox-media',
@ -13,6 +14,8 @@ export class GalleryLightboxMediaComponent implements OnChanges {
@Input() gridMedia: GridMedia; @Input() gridMedia: GridMedia;
@Input() loadMedia = false; @Input() loadMedia = false;
@Input() windowAspect = 1; @Input() windowAspect = 1;
@Input() zoom = 1;
@Input() drag = {x: 0, y: 0};
@ViewChild('video') video: ElementRef<HTMLVideoElement>; @ViewChild('video') video: ElementRef<HTMLVideoElement>;
@ -27,7 +30,14 @@ export class GalleryLightboxMediaComponent implements OnChanges {
photoSrc: string = null; photoSrc: string = null;
private videoProgress = 0; private videoProgress = 0;
constructor(public elementRef: ElementRef) { constructor(public elementRef: ElementRef,
private _sanitizer: DomSanitizer) {
}
get ImageTransform(): SafeStyle {
return this._sanitizer.bypassSecurityTrustStyle('scale(' + this.zoom +
') translate(calc(' + -50 / this.zoom + '% + ' + this.drag.x / this.zoom + 'px), calc(' +
-50 / this.zoom + '% + ' + this.drag.y / this.zoom + 'px))');
} }
ngOnChanges() { ngOnChanges() {