updating thumbnail generation
This commit is contained in:
parent
0a4716e2f8
commit
879deb63d0
@ -39,8 +39,8 @@ export interface PositionMetaData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface GPSMetadata {
|
export interface GPSMetadata {
|
||||||
latitude?: string;
|
latitude?: number;
|
||||||
longitude?: string;
|
longitude?: number;
|
||||||
altitude?: string;
|
altitude?: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -29,6 +29,7 @@ import {StringifyRole} from "./pipes/StringifyRolePipe";
|
|||||||
import {Config} from "./config/Config";
|
import {Config} from "./config/Config";
|
||||||
import {GalleryMapComponent} from "./gallery/map/map.gallery.component";
|
import {GalleryMapComponent} from "./gallery/map/map.gallery.component";
|
||||||
import {GalleryMapLightboxComponent} from "./gallery/map/lightbox/lightbox.map.gallery.component";
|
import {GalleryMapLightboxComponent} from "./gallery/map/lightbox/lightbox.map.gallery.component";
|
||||||
|
import {ThumbnailManagerService} from "./gallery/grid/thumnailManager.service";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -66,6 +67,7 @@ import {GalleryMapLightboxComponent} from "./gallery/map/lightbox/lightbox.map.g
|
|||||||
GalleryService,
|
GalleryService,
|
||||||
AuthenticationService,
|
AuthenticationService,
|
||||||
ThumbnailLoaderService,
|
ThumbnailLoaderService,
|
||||||
|
ThumbnailManagerService,
|
||||||
FullScreenService],
|
FullScreenService],
|
||||||
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|||||||
@ -17,10 +17,21 @@ export class GalleryCacheService {
|
|||||||
let directory: DirectoryDTO = JSON.parse(value);
|
let directory: DirectoryDTO = JSON.parse(value);
|
||||||
|
|
||||||
|
|
||||||
|
//Add references
|
||||||
|
let addDir = (dir: DirectoryDTO) => {
|
||||||
|
dir.photos.forEach((photo: PhotoDTO) => {
|
||||||
|
photo.directory = dir;
|
||||||
|
});
|
||||||
|
|
||||||
|
dir.directories.forEach((directory: DirectoryDTO) => {
|
||||||
|
addDir(directory);
|
||||||
|
directory.parent = dir;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
addDir(directory);
|
||||||
|
|
||||||
directory.photos.forEach((photo: PhotoDTO) => {
|
|
||||||
photo.directory = directory;
|
|
||||||
});
|
|
||||||
|
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
<a class="button btn btn-default" [routerLink]="['/gallery', getDirectoryPath()]"
|
<a #dirContainer class="button btn btn-default" [routerLink]="['/gallery', getDirectoryPath()]"
|
||||||
style="display: inline-block;">
|
style="display: inline-block;">
|
||||||
|
|
||||||
|
|
||||||
<div class="photo-container">
|
<div class="photo-container">
|
||||||
|
|
||||||
<div class="photo" *ngIf="photo" [style.background-image]="'url('+photo.getThumbnailPath()+')'"></div>
|
<div class="photo" *ngIf="thumbnail && thumbnail.available"
|
||||||
|
[style.background-image]="'url('+thumbnail.src+')'"></div>
|
||||||
|
|
||||||
<span *ngIf="!photo" class="glyphicon glyphicon-folder-open no-image" aria-hidden="true">
|
<span *ngIf="!thumbnail || !thumbnail.available" class="glyphicon glyphicon-folder-open no-image"
|
||||||
|
aria-hidden="true">
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import {Component, Input, OnChanges} from "@angular/core";
|
import {Component, Input, OnInit, OnDestroy, ViewChild, ElementRef} from "@angular/core";
|
||||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||||
import {RouterLink} from "@angular/router";
|
import {RouterLink} from "@angular/router";
|
||||||
import {Utils} from "../../../../common/Utils";
|
import {Utils} from "../../../../common/Utils";
|
||||||
import {Photo} from "../Photo";
|
import {Photo} from "../Photo";
|
||||||
|
import {Thumbnail, ThumbnailManagerService} from "../grid/thumnailManager.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gallery-directory',
|
selector: 'gallery-directory',
|
||||||
@ -10,26 +11,36 @@ import {Photo} from "../Photo";
|
|||||||
styleUrls: ['app/gallery/directory/directory.gallery.component.css'],
|
styleUrls: ['app/gallery/directory/directory.gallery.component.css'],
|
||||||
providers: [RouterLink],
|
providers: [RouterLink],
|
||||||
})
|
})
|
||||||
export class GalleryDirectoryComponent implements OnChanges {
|
export class GalleryDirectoryComponent implements OnInit,OnDestroy {
|
||||||
@Input() directory: DirectoryDTO;
|
@Input() directory: DirectoryDTO;
|
||||||
photo: Photo = null;
|
@ViewChild("dirContainer") container: ElementRef;
|
||||||
|
thumbnail: Thumbnail = null;
|
||||||
|
|
||||||
constructor() {
|
constructor(private thumbnailService: ThumbnailManagerService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnInit() {
|
||||||
setImmediate(() => {
|
if (this.directory.photos.length > 0) {
|
||||||
if (this.directory.photos.length > 0) {
|
this.thumbnail = this.thumbnailService.getThumbnail(new Photo(this.directory.photos[0], 100, 100));
|
||||||
this.photo = new Photo(this.directory.photos[0], 100, 100);
|
|
||||||
console.log(this.photo);
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
//TODO: implement scroll
|
||||||
|
isInView(): boolean {
|
||||||
|
return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight
|
||||||
|
&& document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDirectoryPath() {
|
getDirectoryPath() {
|
||||||
return Utils.concatUrls(this.directory.path, this.directory.name);
|
return Utils.concatUrls(this.directory.path, this.directory.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.thumbnail != null) {
|
||||||
|
this.thumbnail.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<gallery-directory *ngFor="let directory of _galleryService.content.directory.directories"
|
<gallery-directory *ngFor="let directory of _galleryService.content.directory.directories"
|
||||||
[directory]="directory"></gallery-directory>
|
[directory]="directory"></gallery-directory>
|
||||||
|
|
||||||
<gallery-map [photos]="_galleryService.content.directory.photos"></gallery-map>
|
<gallery-map [photos]="_galleryService.content.directory.photos"></gallery-map>
|
||||||
<gallery-grid [photos]="_galleryService.content.directory.photos" [lightbox]="lightbox"></gallery-grid>
|
<gallery-grid [photos]="_galleryService.content.directory.photos" [lightbox]="lightbox"></gallery-grid>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -10,25 +10,26 @@ import {GalleryCacheService} from "./cache.gallery.service";
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class GalleryService {
|
export class GalleryService {
|
||||||
|
|
||||||
public content:ContentWrapper;
|
public content: ContentWrapper;
|
||||||
private lastDirectory: DirectoryDTO;
|
private lastDirectory: DirectoryDTO;
|
||||||
private searchId:any;
|
private searchId: any;
|
||||||
|
|
||||||
constructor(private networkService:NetworkService, private galleryCacheService:GalleryCacheService) {
|
constructor(private networkService: NetworkService, private galleryCacheService: GalleryCacheService) {
|
||||||
this.content = new ContentWrapper();
|
this.content = new ContentWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastRequest: {directory: any} = {
|
lastRequest: {directory: string} = {
|
||||||
directory: null
|
directory: null
|
||||||
};
|
};
|
||||||
public getDirectory(directoryName:string):Promise<Message<ContentWrapper>> {
|
|
||||||
|
public getDirectory(directoryName: string): Promise<Message<ContentWrapper>> {
|
||||||
this.content = new ContentWrapper();
|
this.content = new ContentWrapper();
|
||||||
|
|
||||||
this.content.directory = this.galleryCacheService.getDirectory(directoryName);
|
this.content.directory = this.galleryCacheService.getDirectory(directoryName);
|
||||||
this.content.searchResult = null;
|
this.content.searchResult = null;
|
||||||
this.lastRequest.directory = directoryName;
|
this.lastRequest.directory = directoryName;
|
||||||
return this.networkService.getJson("/gallery/content/" + directoryName).then(
|
return this.networkService.getJson("/gallery/content/" + directoryName).then(
|
||||||
(message:Message<ContentWrapper>) => {
|
(message: Message<ContentWrapper>) => {
|
||||||
if (!message.error && message.result) {
|
if (!message.error && message.result) {
|
||||||
|
|
||||||
this.galleryCacheService.setDirectory(message.result.directory); //save it before adding references
|
this.galleryCacheService.setDirectory(message.result.directory); //save it before adding references
|
||||||
@ -36,6 +37,8 @@ export class GalleryService {
|
|||||||
if (this.lastRequest.directory != directoryName) {
|
if (this.lastRequest.directory != directoryName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Add references
|
||||||
let addDir = (dir: DirectoryDTO) => {
|
let addDir = (dir: DirectoryDTO) => {
|
||||||
dir.photos.forEach((photo: PhotoDTO) => {
|
dir.photos.forEach((photo: PhotoDTO) => {
|
||||||
photo.directory = dir;
|
photo.directory = dir;
|
||||||
@ -51,7 +54,6 @@ export class GalleryService {
|
|||||||
addDir(message.result.directory);
|
addDir(message.result.directory);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.lastDirectory = message.result.directory;
|
this.lastDirectory = message.result.directory;
|
||||||
this.content = message.result;
|
this.content = message.result;
|
||||||
}
|
}
|
||||||
@ -60,7 +62,7 @@ export class GalleryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: cache
|
//TODO: cache
|
||||||
public search(text:string, type?:SearchTypes):Promise<Message<ContentWrapper>> {
|
public search(text: string, type?: SearchTypes): Promise<Message<ContentWrapper>> {
|
||||||
clearTimeout(this.searchId);
|
clearTimeout(this.searchId);
|
||||||
if (text === null || text === '') {
|
if (text === null || text === '') {
|
||||||
return Promise.resolve(new Message(null, null));
|
return Promise.resolve(new Message(null, null));
|
||||||
@ -72,7 +74,7 @@ export class GalleryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.networkService.getJson(queryString).then(
|
return this.networkService.getJson(queryString).then(
|
||||||
(message:Message<ContentWrapper>) => {
|
(message: Message<ContentWrapper>) => {
|
||||||
if (!message.error && message.result) {
|
if (!message.error && message.result) {
|
||||||
this.content = message.result;
|
this.content = message.result;
|
||||||
}
|
}
|
||||||
@ -81,7 +83,7 @@ export class GalleryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: cache (together with normal search)
|
//TODO: cache (together with normal search)
|
||||||
public instantSearch(text:string):Promise<Message<ContentWrapper>> {
|
public instantSearch(text: string): Promise<Message<ContentWrapper>> {
|
||||||
if (text === null || text === '') {
|
if (text === null || text === '') {
|
||||||
this.content.directory = this.lastDirectory;
|
this.content.directory = this.lastDirectory;
|
||||||
this.content.searchResult = null;
|
this.content.searchResult = null;
|
||||||
@ -99,7 +101,7 @@ export class GalleryService {
|
|||||||
}, 3000); //TODO: set timeout to config
|
}, 3000); //TODO: set timeout to config
|
||||||
|
|
||||||
return this.networkService.getJson("/instant-search/" + text).then(
|
return this.networkService.getJson("/instant-search/" + text).then(
|
||||||
(message:Message<ContentWrapper>) => {
|
(message: Message<ContentWrapper>) => {
|
||||||
if (!message.error && message.result) {
|
if (!message.error && message.result) {
|
||||||
this.content = message.result;
|
this.content = message.result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<div #photoContainer class="photo-container" (mouseover)="hover()" (mouseout)="mouseOut()">
|
<div #photoContainer class="photo-container" (mouseover)="hover()" (mouseout)="mouseOut()">
|
||||||
<img #img [src]="image.src" [hidden]="!image.show || loading.show" (load)="onImageLoad()">
|
<img #img [src]="thumbnail.src" [hidden]="!thumbnail.available">
|
||||||
|
|
||||||
<gallery-grid-photo-loading [animate]="loading.animate" *ngIf="loading.show">
|
<gallery-grid-photo-loading [animate]="thumbnail.loading" *ngIf="!thumbnail.available">
|
||||||
</gallery-grid-photo-loading>
|
</gallery-grid-photo-loading>
|
||||||
|
|
||||||
<!--Info box -->
|
<!--Info box -->
|
||||||
|
|||||||
@ -1,15 +1,10 @@
|
|||||||
import {Component, Input, ElementRef, ViewChild, OnInit, AfterViewInit, OnDestroy} from "@angular/core";
|
import {Component, Input, ElementRef, ViewChild, OnInit, OnDestroy} from "@angular/core";
|
||||||
import {IRenderable, Dimension} from "../../../model/IRenderable";
|
import {IRenderable, Dimension} from "../../../model/IRenderable";
|
||||||
import {GridPhoto} from "../GridPhoto";
|
import {GridPhoto} from "../GridPhoto";
|
||||||
import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem";
|
import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem";
|
||||||
import {RouterLink} from "@angular/router";
|
import {RouterLink} from "@angular/router";
|
||||||
import {Config} from "../../../config/Config";
|
import {Config} from "../../../config/Config";
|
||||||
import {
|
import {Thumbnail, ThumbnailManagerService} from "../thumnailManager.service";
|
||||||
ThumbnailLoaderService,
|
|
||||||
ThumbnailTaskEntity,
|
|
||||||
ThumbnailLoadingListener,
|
|
||||||
ThumbnailLoadingPriority
|
|
||||||
} from "../thumnailLoader.service";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gallery-grid-photo',
|
selector: 'gallery-grid-photo',
|
||||||
@ -17,24 +12,24 @@ import {
|
|||||||
styleUrls: ['app/gallery/grid/photo/photo.grid.gallery.component.css'],
|
styleUrls: ['app/gallery/grid/photo/photo.grid.gallery.component.css'],
|
||||||
providers: [RouterLink],
|
providers: [RouterLink],
|
||||||
})
|
})
|
||||||
export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit, OnDestroy {
|
export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy {
|
||||||
@Input() gridPhoto: GridPhoto;
|
@Input() gridPhoto: GridPhoto;
|
||||||
@ViewChild("img") imageRef: ElementRef;
|
@ViewChild("img") imageRef: ElementRef;
|
||||||
@ViewChild("info") infoDiv: ElementRef;
|
@ViewChild("info") infoDiv: ElementRef;
|
||||||
@ViewChild("photoContainer") container: ElementRef;
|
@ViewChild("photoContainer") container: ElementRef;
|
||||||
|
|
||||||
|
thumbnail: Thumbnail;
|
||||||
|
/*
|
||||||
|
image = {
|
||||||
|
src: '',
|
||||||
|
show: false
|
||||||
|
};
|
||||||
|
|
||||||
image = {
|
loading = {
|
||||||
src: '',
|
animate: false,
|
||||||
show: false
|
show: true
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
loading = {
|
|
||||||
animate: false,
|
|
||||||
show: true
|
|
||||||
};
|
|
||||||
|
|
||||||
thumbnailTask: ThumbnailTaskEntity = null;
|
|
||||||
|
|
||||||
infoStyle = {
|
infoStyle = {
|
||||||
height: 0,
|
height: 0,
|
||||||
@ -46,65 +41,67 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit
|
|||||||
|
|
||||||
wasInView: boolean = null;
|
wasInView: boolean = null;
|
||||||
|
|
||||||
constructor(private thumbnailService: ThumbnailLoaderService) {
|
constructor(private thumbnailService: ThumbnailManagerService) {
|
||||||
this.SearchTypes = SearchTypes;
|
this.SearchTypes = SearchTypes;
|
||||||
this.searchEnabled = Config.Client.Search.searchEnabled;
|
this.searchEnabled = Config.Client.Search.searchEnabled;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.loading.show = true;
|
this.thumbnail = this.thumbnailService.getThumbnail(this.gridPhoto);
|
||||||
//set up befoar adding task to thumbnail generator
|
/* this.loading.show = true;
|
||||||
if (this.gridPhoto.isThumbnailAvailable()) {
|
//set up before adding task to thumbnail generator
|
||||||
this.image.src = this.gridPhoto.getThumbnailPath();
|
if (this.gridPhoto.isThumbnailAvailable()) {
|
||||||
this.image.show = true;
|
this.image.src = this.gridPhoto.getThumbnailPath();
|
||||||
} else if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
this.image.show = true;
|
||||||
this.image.src = this.gridPhoto.getReplacementThumbnailPath();
|
} else if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
||||||
this.image.show = true;
|
this.image.src = this.gridPhoto.getReplacementThumbnailPath();
|
||||||
}
|
this.image.show = true;
|
||||||
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
/*
|
||||||
//schedule change after Angular checks the model
|
ngAfterViewInit() {
|
||||||
if (!this.gridPhoto.isThumbnailAvailable()) {
|
//schedule change after Angular checks the model
|
||||||
setImmediate(() => {
|
if (!this.gridPhoto.isThumbnailAvailable()) {
|
||||||
|
setImmediate(() => {
|
||||||
|
|
||||||
let listener: ThumbnailLoadingListener = {
|
let listener: ThumbnailLoadingListener = {
|
||||||
onStartedLoading: () => { //onLoadStarted
|
onStartedLoading: () => { //onLoadStarted
|
||||||
this.loading.animate = true;
|
this.loading.animate = true;
|
||||||
},
|
},
|
||||||
onLoad: () => {//onLoaded
|
onLoad: () => {//onLoaded
|
||||||
this.image.src = this.gridPhoto.getThumbnailPath();
|
this.image.src = this.gridPhoto.getThumbnailPath();
|
||||||
this.image.show = true;
|
this.image.show = true;
|
||||||
this.loading.show = false;
|
this.loading.show = false;
|
||||||
this.thumbnailTask = null;
|
this.thumbnailTask = null;
|
||||||
},
|
},
|
||||||
onError: (error) => {//onError
|
onError: (error) => {//onError
|
||||||
this.thumbnailTask = null;
|
this.thumbnailTask = null;
|
||||||
//TODO: handle error
|
//TODO: handle error
|
||||||
//TODO: not an error if its from cache
|
//TODO: not an error if its from cache
|
||||||
console.error("something bad happened");
|
console.error("something bad happened");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
||||||
this.thumbnailTask = this.thumbnailService.loadImage(this.gridPhoto, ThumbnailLoadingPriority.medium, listener);
|
this.thumbnailTask = this.thumbnailService.loadImage(this.gridPhoto, ThumbnailLoadingPriority.medium, listener);
|
||||||
} else {
|
} else {
|
||||||
this.thumbnailTask = this.thumbnailService.loadImage(this.gridPhoto, ThumbnailLoadingPriority.high, listener);
|
this.thumbnailTask = this.thumbnailService.loadImage(this.gridPhoto, ThumbnailLoadingPriority.high, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.thumbnailTask != null) {
|
this.thumbnail.destroy();
|
||||||
this.thumbnailService.removeTask(this.thumbnailTask);
|
/*
|
||||||
this.thumbnailTask = null;
|
if (this.thumbnailTask != null) {
|
||||||
}
|
this.thumbnailService.removeTask(this.thumbnailTask);
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -115,24 +112,10 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit
|
|||||||
|
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if (this.thumbnailTask != null) {
|
let isInView = this.isInView();
|
||||||
let isInView = this.isInView();
|
if (this.wasInView != isInView) {
|
||||||
if (this.wasInView != isInView) {
|
this.wasInView = isInView;
|
||||||
this.wasInView = isInView;
|
this.thumbnail.Visible = isInView;
|
||||||
if (isInView === true) {
|
|
||||||
if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
|
||||||
} else {
|
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.gridPhoto.isReplacementThumbnailAvailable()) {
|
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.low;
|
|
||||||
} else {
|
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,10 +140,11 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, AfterViewInit
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onImageLoad() {
|
/*
|
||||||
this.loading.show = false;
|
onImageLoad() {
|
||||||
}
|
this.loading.show = false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
public getDimension(): Dimension {
|
public getDimension(): Dimension {
|
||||||
return <Dimension>{
|
return <Dimension>{
|
||||||
top: this.imageRef.nativeElement.offsetTop,
|
top: this.imageRef.nativeElement.offsetTop,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {GridPhoto} from "./GridPhoto";
|
|
||||||
import {Config} from "../../config/Config";
|
import {Config} from "../../config/Config";
|
||||||
import {GalleryCacheService} from "../cache.gallery.service";
|
import {GalleryCacheService} from "../cache.gallery.service";
|
||||||
|
import {Photo} from "../Photo";
|
||||||
|
|
||||||
export enum ThumbnailLoadingPriority{
|
export enum ThumbnailLoadingPriority{
|
||||||
high, medium, low
|
high, medium, low
|
||||||
@ -36,12 +36,12 @@ export class ThumbnailLoaderService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadImage(gridPhoto: GridPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
||||||
|
|
||||||
let tmp: ThumbnailTask = null;
|
let tmp: ThumbnailTask = null;
|
||||||
//is image already qued?
|
//is image already qued?
|
||||||
for (let i = 0; i < this.que.length; i++) {
|
for (let i = 0; i < this.que.length; i++) {
|
||||||
if (this.que[i].gridPhoto.getThumbnailPath() == gridPhoto.getThumbnailPath()) {
|
if (this.que[i].photo.getThumbnailPath() == photo.getThumbnailPath()) {
|
||||||
tmp = this.que[i];
|
tmp = this.que[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ export class ThumbnailLoaderService {
|
|||||||
|
|
||||||
} else {//create new task
|
} else {//create new task
|
||||||
this.que.push({
|
this.que.push({
|
||||||
gridPhoto: gridPhoto,
|
photo: photo,
|
||||||
inProgress: false,
|
inProgress: false,
|
||||||
taskEntities: [thumbnailTaskEntity]
|
taskEntities: [thumbnailTaskEntity]
|
||||||
});
|
});
|
||||||
@ -129,8 +129,8 @@ export class ThumbnailLoaderService {
|
|||||||
|
|
||||||
let curImg = new Image();
|
let curImg = new Image();
|
||||||
curImg.onload = () => {
|
curImg.onload = () => {
|
||||||
task.gridPhoto.thumbnailLoaded();
|
task.photo.thumbnailLoaded();
|
||||||
this.galleryChacheService.photoUpdated(task.gridPhoto.photo);
|
this.galleryChacheService.photoUpdated(task.photo.photo);
|
||||||
task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onLoad());
|
task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onLoad());
|
||||||
|
|
||||||
this.taskReady(task);
|
this.taskReady(task);
|
||||||
@ -146,7 +146,7 @@ export class ThumbnailLoaderService {
|
|||||||
this.run();
|
this.run();
|
||||||
};
|
};
|
||||||
|
|
||||||
curImg.src = task.gridPhoto.getThumbnailPath();
|
curImg.src = task.photo.getThumbnailPath();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,13 +159,12 @@ export interface ThumbnailLoadingListener {
|
|||||||
|
|
||||||
|
|
||||||
export interface ThumbnailTaskEntity {
|
export interface ThumbnailTaskEntity {
|
||||||
|
|
||||||
priority: ThumbnailLoadingPriority;
|
priority: ThumbnailLoadingPriority;
|
||||||
listener: ThumbnailLoadingListener;
|
listener: ThumbnailLoadingListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThumbnailTask {
|
interface ThumbnailTask {
|
||||||
gridPhoto: GridPhoto;
|
photo: Photo;
|
||||||
inProgress: boolean;
|
inProgress: boolean;
|
||||||
taskEntities: Array<ThumbnailTaskEntity>;
|
taskEntities: Array<ThumbnailTaskEntity>;
|
||||||
|
|
||||||
|
|||||||
109
frontend/app/gallery/grid/thumnailManager.service.ts
Normal file
109
frontend/app/gallery/grid/thumnailManager.service.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {Photo} from "../Photo";
|
||||||
|
import {ThumbnailLoaderService, ThumbnailLoadingListener, ThumbnailTaskEntity} from "./thumnailLoader.service";
|
||||||
|
|
||||||
|
export enum ThumbnailLoadingPriority{
|
||||||
|
high, medium, low
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ThumbnailManagerService {
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private thumbnailLoader: ThumbnailLoaderService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public getThumbnail(photo: Photo) {
|
||||||
|
return new Thumbnail(photo, this.thumbnailLoader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class Thumbnail {
|
||||||
|
|
||||||
|
private available: boolean = false;
|
||||||
|
private src: string = null;
|
||||||
|
private loading: boolean = false;
|
||||||
|
private thumbnailTask: ThumbnailTaskEntity;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private photo: Photo, private thumbnailService: ThumbnailLoaderService) {
|
||||||
|
if (this.photo.isThumbnailAvailable()) {
|
||||||
|
this.src = this.photo.getThumbnailPath();
|
||||||
|
this.available = true;
|
||||||
|
} else if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
|
this.src = this.photo.getReplacementThumbnailPath();
|
||||||
|
this.available = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.photo.isThumbnailAvailable()) {
|
||||||
|
setImmediate(() => {
|
||||||
|
|
||||||
|
let listener: ThumbnailLoadingListener = {
|
||||||
|
onStartedLoading: () => { //onLoadStarted
|
||||||
|
this.loading = true;
|
||||||
|
},
|
||||||
|
onLoad: () => {//onLoaded
|
||||||
|
this.src = this.photo.getThumbnailPath();
|
||||||
|
this.available = true;
|
||||||
|
this.loading = false;
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
},
|
||||||
|
onError: (error) => {//onError
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
//TODO: handle error
|
||||||
|
//TODO: not an error if its from cache
|
||||||
|
console.error("something bad happened");
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
|
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.medium, listener);
|
||||||
|
} else {
|
||||||
|
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.high, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
set Visible(visible: boolean) {
|
||||||
|
if (visible === true) {
|
||||||
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
||||||
|
} else {
|
||||||
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.low;
|
||||||
|
} else {
|
||||||
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get Available() {
|
||||||
|
return this.available;
|
||||||
|
}
|
||||||
|
|
||||||
|
get Src() {
|
||||||
|
return this.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
get Loading() {
|
||||||
|
return this.loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this.thumbnailTask != null) {
|
||||||
|
this.thumbnailService.removeTask(this.thumbnailTask);
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ export class GalleryMapLightboxComponent implements OnChanges {
|
|||||||
public mapDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0};
|
public mapDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0};
|
||||||
private visible = false;
|
private visible = false;
|
||||||
private opacity = 1.0;
|
private opacity = 1.0;
|
||||||
mapPhotos: Array<{latitude: string, longitude: string, iconUrl}> = [];
|
mapPhotos: Array<{latitude: number, longitude: number, iconUrl}> = [];
|
||||||
mapCenter = {latitude: "0", longitude: "0"};
|
mapCenter = {latitude: 0, longitude: 0};
|
||||||
|
|
||||||
@ViewChild("root") elementRef: ElementRef;
|
@ViewChild("root") elementRef: ElementRef;
|
||||||
|
|
||||||
@ -33,21 +33,10 @@ export class GalleryMapLightboxComponent implements OnChanges {
|
|||||||
|
|
||||||
//TODO: fix zooming
|
//TODO: fix zooming
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.mapPhotos = this.photos.filter(p => {
|
if (this.visible == false) {
|
||||||
return p.metadata && p.metadata.positionData && p.metadata.positionData.GPSData;
|
return;
|
||||||
}).map(p => {
|
|
||||||
return {
|
|
||||||
latitude: p.metadata.positionData.GPSData.latitude,
|
|
||||||
longitude: p.metadata.positionData.GPSData.longitude,
|
|
||||||
iconUrl: Utils.concatUrls("/api/gallery/content/", p.directory.path, p.directory.name, p.name, "icon")
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.mapPhotos.length > 0) {
|
|
||||||
this.mapCenter = this.mapPhotos[0];
|
|
||||||
}
|
}
|
||||||
|
this.showImages();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public show(position: Dimension) {
|
public show(position: Dimension) {
|
||||||
@ -65,6 +54,7 @@ export class GalleryMapLightboxComponent implements OnChanges {
|
|||||||
this.map.triggerResize();
|
this.map.triggerResize();
|
||||||
|
|
||||||
document.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
document.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
||||||
|
this.showImages();
|
||||||
|
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this.lightboxDimension = <Dimension>{
|
this.lightboxDimension = <Dimension>{
|
||||||
@ -91,11 +81,28 @@ export class GalleryMapLightboxComponent implements OnChanges {
|
|||||||
this.opacity = 0.0;
|
this.opacity = 0.0;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
this.mapPhotos = [];
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showImages() {
|
||||||
|
this.mapPhotos = this.photos.filter(p => {
|
||||||
|
return p.metadata && p.metadata.positionData && p.metadata.positionData.GPSData;
|
||||||
|
}).map(p => {
|
||||||
|
return {
|
||||||
|
latitude: p.metadata.positionData.GPSData.latitude,
|
||||||
|
longitude: p.metadata.positionData.GPSData.longitude,
|
||||||
|
iconUrl: Utils.concatUrls("/api/gallery/content/", p.directory.path, p.directory.name, p.name, "icon")
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.mapPhotos.length > 0) {
|
||||||
|
this.mapCenter = this.mapPhotos[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private getBodyScrollTop(): number {
|
private getBodyScrollTop(): number {
|
||||||
return window.scrollY;
|
return window.scrollY;
|
||||||
|
|||||||
@ -13,8 +13,8 @@ export class GalleryMapComponent implements OnChanges, IRenderable {
|
|||||||
@Input() photos: Array<PhotoDTO>;
|
@Input() photos: Array<PhotoDTO>;
|
||||||
@ViewChild(GalleryMapLightboxComponent) mapLightbox: GalleryMapLightboxComponent;
|
@ViewChild(GalleryMapLightboxComponent) mapLightbox: GalleryMapLightboxComponent;
|
||||||
|
|
||||||
mapPhotos: Array<{latitude: string, longitude: string, iconUrl}> = [];
|
mapPhotos: Array<{latitude: number, longitude: number, iconUrl}> = [];
|
||||||
mapCenter = {latitude: "0", longitude: "0"};
|
mapCenter = {latitude: 0, longitude: 0};
|
||||||
@ViewChild("map") map: ElementRef;
|
@ViewChild("map") map: ElementRef;
|
||||||
|
|
||||||
//TODO: fix zooming
|
//TODO: fix zooming
|
||||||
|
|||||||
@ -6,12 +6,12 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"suppressImplicitAnyIndexErrors": false,
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2015",
|
"es2015",
|
||||||
"dom",
|
"dom",
|
||||||
"es2015.promise"
|
"es2015.promise"
|
||||||
],
|
],
|
||||||
"suppressImplicitAnyIndexErrors": false,
|
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"./node_modules/@types"
|
"./node_modules/@types"
|
||||||
]
|
]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user