From 0cfa60143a1de7913d112892e2b4ef4cd0321df5 Mon Sep 17 00:00:00 2001 From: Braun Patrik Date: Sat, 9 Apr 2016 15:19:25 +0200 Subject: [PATCH] implementing responsive photo grid system --- backend/model/GalleryManager.ts | 4 +- common/entities/Photo.ts | 2 +- frontend/app/gallery/gallery.component.html | 4 +- frontend/app/gallery/gallery.component.ts | 3 +- frontend/app/gallery/grid/GridRowBuilder.ts | 65 ++++++++++++++++ .../gallery/grid/grid.gallery.component.css | 7 ++ .../gallery/grid/grid.gallery.component.html | 13 ++++ .../gallery/grid/grid.gallery.component.ts | 75 +++++++++++++++++++ .../photo/photo.gallery.component.html | 2 +- package.json | 1 + typings.json | 1 + 11 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 frontend/app/gallery/grid/GridRowBuilder.ts create mode 100644 frontend/app/gallery/grid/grid.gallery.component.css create mode 100644 frontend/app/gallery/grid/grid.gallery.component.html create mode 100644 frontend/app/gallery/grid/grid.gallery.component.ts diff --git a/backend/model/GalleryManager.ts b/backend/model/GalleryManager.ts index c6e9d30..3d463ee 100644 --- a/backend/model/GalleryManager.ts +++ b/backend/model/GalleryManager.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as mime from 'mime'; +import * as sizeOf from 'image-size'; import {Directory} from "../../common/entities/Directory"; import {Photo} from "../../common/entities/Photo"; @@ -30,7 +31,8 @@ export class GalleryManager { } if(GalleryManager.isImage(fullFilePath)){ - directory.photos.push(new Photo(1,file)); + let dimensions = sizeOf(fullFilePath); + directory.photos.push(new Photo(1,file,dimensions.width,dimensions.height)); } } diff --git a/common/entities/Photo.ts b/common/entities/Photo.ts index cbc5051..9f2366a 100644 --- a/common/entities/Photo.ts +++ b/common/entities/Photo.ts @@ -1,4 +1,4 @@ export class Photo{ - constructor(public id:number,public name:string){} + constructor(public id:number,public name:string,public width:number,public height:number){} } \ No newline at end of file diff --git a/frontend/app/gallery/gallery.component.html b/frontend/app/gallery/gallery.component.html index ea85b8a..a33967a 100644 --- a/frontend/app/gallery/gallery.component.html +++ b/frontend/app/gallery/gallery.component.html @@ -3,6 +3,4 @@
-
- -
\ No newline at end of file + \ No newline at end of file diff --git a/frontend/app/gallery/gallery.component.ts b/frontend/app/gallery/gallery.component.ts index 497b500..c336090 100644 --- a/frontend/app/gallery/gallery.component.ts +++ b/frontend/app/gallery/gallery.component.ts @@ -8,11 +8,12 @@ import {Directory} from "../../../common/entities/Directory"; import {Message} from "../../../common/entities/Message"; import {GalleryPhotoComponent} from "./photo/photo.gallery.component"; import {GalleryDirectoryComponent} from "./directory/directory.gallery.component"; +import {GalleryGridComponent} from "./grid/grid.gallery.component"; @Component({ selector: 'gallery', templateUrl: 'app/gallery/gallery.component.html', - directives:[GalleryPhotoComponent, + directives:[GalleryGridComponent, GalleryDirectoryComponent] }) export class GalleryComponent implements OnInit{ diff --git a/frontend/app/gallery/grid/GridRowBuilder.ts b/frontend/app/gallery/grid/GridRowBuilder.ts new file mode 100644 index 0000000..0a57873 --- /dev/null +++ b/frontend/app/gallery/grid/GridRowBuilder.ts @@ -0,0 +1,65 @@ + +import {Photo} from "../../../../common/entities/Photo"; + +export class GridRowBuilder{ + + private photoRow:Array = []; + + private photoIndex:number = 0; //index of the last pushed photo to the photoRow + + + constructor(private photos:Array, private startIndex:number, private photoMargin:number, private containerWidth:number){ + this.photoIndex = startIndex; + } + + public addPhotos(number:number){ + for(let i = 0; i < number; i++){ + this.addPhoto(); + } + } + + public addPhoto():boolean{ + if(this.photoIndex + 1 > this.photos.length){ + return false; + } + this.photoRow.push(this.photos[this.photoIndex]); + this.photoIndex++; + return true; + } + + public removePhoto():boolean{ + if(this.photoIndex - 1 < this.startIndex){ + return false; + } + this.photoIndex--; + this.photoRow.pop(); + return true; + } + + public getPhotoRow():Array{ + return this.photoRow; + } + + public adjustRowHeightBetween(minHeight:number,maxHeight:number){ + while (this.calcRowHeight() > maxHeight && this.addPhoto() === true) { //row too high -> add more images + } + + while (this.calcRowHeight() < minHeight && this.removePhoto() === true) { //roo too small -> remove images + } + + //keep at least one photo int thr row + if(this.photoRow.length <= 0){ + this.addPhoto(); + } + } + + public calcRowHeight():number { + let width = 0; + for(let i = 0; i < this.photoRow.length; i++){ + width += ((this.photoRow[i].width) / (this.photoRow[i].height)); //summing up aspect ratios + } + let height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; //cant be equal -> width-1 + + return height +(this.photoMargin * 2); + }; +} \ No newline at end of file diff --git a/frontend/app/gallery/grid/grid.gallery.component.css b/frontend/app/gallery/grid/grid.gallery.component.css new file mode 100644 index 0000000..606e035 --- /dev/null +++ b/frontend/app/gallery/grid/grid.gallery.component.css @@ -0,0 +1,7 @@ +div { + display: block; +} +gallery-photo { + display: inline-block; + overflow: hidden; +} \ No newline at end of file diff --git a/frontend/app/gallery/grid/grid.gallery.component.html b/frontend/app/gallery/grid/grid.gallery.component.html new file mode 100644 index 0000000..2d49059 --- /dev/null +++ b/frontend/app/gallery/grid/grid.gallery.component.html @@ -0,0 +1,13 @@ +
+ + + +
\ No newline at end of file diff --git a/frontend/app/gallery/grid/grid.gallery.component.ts b/frontend/app/gallery/grid/grid.gallery.component.ts new file mode 100644 index 0000000..9b802db --- /dev/null +++ b/frontend/app/gallery/grid/grid.gallery.component.ts @@ -0,0 +1,75 @@ +/// + +import {Component, Input, ElementRef, OnChanges} from 'angular2/core'; +import {Directory} from "../../../../common/entities/Directory"; +import {Photo} from "../../../../common/entities/Photo"; +import {GalleryPhotoComponent} from "../photo/photo.gallery.component"; +import {GridRowBuilder} from "./GridRowBuilder"; + +@Component({ + selector: 'gallery-grid', + templateUrl: 'app/gallery/grid/grid.gallery.component.html', + styleUrls: ['app/gallery/grid/grid.gallery.component.css'], + directives:[GalleryPhotoComponent] +}) +export class GalleryGridComponent implements OnChanges{ + + @Input() directory:Directory; + photosToRender:Array = []; + private IMAGE_MARGIN = 2; + private TARGET_COL_COUNT = 5; + private MIN_ROW_COUNT = 2; + private MAX_ROW_COUNT = 5; + + constructor(private elementRef: ElementRef) { + } + + ngOnChanges(){ + this.renderPhotos(); + } + + private renderPhotos() { + let maxRowHeight = window.innerHeight / this.MIN_ROW_COUNT; + let minRowHeight = window.innerHeight / this.MAX_ROW_COUNT; + + this.photosToRender = []; + let i = 0; + while (i < this.directory.photos.length ) { + + let photoRowBuilder = new GridRowBuilder(this.directory.photos,i,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.width / photo.height); + this.photosToRender.push(new GridPhoto(photo,imageWidth,imageHeight)); + }); + + i+= photoRowBuilder.getPhotoRow().length; + } + } + + onResize() { + this.renderPhotos(); + } + + private getContainerWidth(): number{ + if(typeof this.elementRef.nativeElement.firstElementChild === 'undefined' || + this.elementRef.nativeElement.firstElementChild === null){ + return 0; + } + return this.elementRef.nativeElement.firstElementChild.clientWidth; + } + + +} + + +class GridPhoto { + constructor(public photo:Photo, public renderWidth:number, public renderHeight:number){ + + } +} diff --git a/frontend/app/gallery/photo/photo.gallery.component.html b/frontend/app/gallery/photo/photo.gallery.component.html index 4e64df5..80ae887 100644 --- a/frontend/app/gallery/photo/photo.gallery.component.html +++ b/frontend/app/gallery/photo/photo.gallery.component.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/package.json b/package.json index e84e0ec..2f7f7db 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "debug": "^2.2.0", "express": "^4.13.4", "express-session": "^1.13.0", + "image-size": "^0.5.0", "jimp": "^0.2.21", "mime": "^1.3.4", "morgan": "^1.7.0", diff --git a/typings.json b/typings.json index 5142257..32f9ab7 100644 --- a/typings.json +++ b/typings.json @@ -6,6 +6,7 @@ "debug": "github:DefinitelyTyped/DefinitelyTyped/debug/debug.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e", "express": "github:DefinitelyTyped/DefinitelyTyped/express/express.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e", "express-session": "registry:dt/express-session#0.0.0+20160331200931", + "image-size": "registry:dt/image-size#0.0.0+20160223165602", "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#d22516f9f089de107d7e7d5938566377370631f6", "mime": "github:DefinitelyTyped/DefinitelyTyped/mime/mime.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e", "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#0d622d857f97d44ea7dcad2b3edec1f23c48fe9e",