mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-12 04:23:09 +02:00
improving statistic design #654
This commit is contained in:
parent
fdea2b570f
commit
5ff243310e
@ -5,10 +5,13 @@
|
||||
<div class="col-md-1-half col-12 d-table">
|
||||
</div>
|
||||
<div class="col-md-9 col-12 date-frequency" *ngIf="showStatistic">
|
||||
<ng-container *ngFor="let freq of MediaCountOverTime; count as length">
|
||||
<ng-container *ngFor="let freq of filterService.statistic; count as length">
|
||||
<div class="d-inline-block date-frequency-column"
|
||||
[style.width.%]="(1/length)*100"
|
||||
[title]="(freq.date | date: 'medium') + ' (' + freq.count+')'">
|
||||
container="body"
|
||||
triggers="mouseenter:mouseleave"
|
||||
placement="bottom start"
|
||||
[popover]="(freq.date | date: 'medium') + ' (' + freq.count+')'">
|
||||
<div class=" text-center " [style.height.%]="100-(freq.count/freq.max)*100">
|
||||
<div class="d-none d-lg-block" *ngIf="freq.count < freq.max/2">{{freq.count}}</div>
|
||||
</div>
|
||||
@ -18,7 +21,7 @@
|
||||
[style.height.%]="(freq.count/freq.max)*100">
|
||||
<div class="d-none d-lg-block" *ngIf="freq.count >= freq.max/2">{{freq.count}}</div>
|
||||
</div>
|
||||
<div class="text-center d-none d-md-block">
|
||||
<div class="text-center d-none d-xl-block overflow-x-hidden text-nowrap ps-1 pe-1">
|
||||
{{freq.date | date: freq.dateStr}}
|
||||
</div>
|
||||
</div>
|
||||
@ -28,8 +31,8 @@
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="position-absolute">
|
||||
<div class="text-center">
|
||||
<div class="position-absolute" *ngIf="filterService.statistic.length>1">
|
||||
<div class="text-md-center">
|
||||
<span
|
||||
[class.oi-chevron-bottom]="showStatistic"
|
||||
[class.oi-chevron-top]="!showStatistic"
|
||||
|
@ -54,87 +54,6 @@ export class GalleryFilterComponent implements OnInit, OnDestroy {
|
||||
return this.filterService.activeFilters.value;
|
||||
}
|
||||
|
||||
get MediaCountOverTime(): { date: Date, endDate: Date, dateStr: string, count: number, max: number }[] {
|
||||
if (!this.filterService.prefiltered ||
|
||||
!this.filterService.prefiltered.media ||
|
||||
this.filterService.prefiltered.media.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const ret: { date: Date, endDate: Date, dateStr: string, count: number, max: number }[] = [];
|
||||
const diff = (this.ActiveFilters.dateFilter.maxDate - this.ActiveFilters.dateFilter.minDate) / 1000;
|
||||
const H = 60 * 60;
|
||||
const D = H * 24;
|
||||
const M = D * 30;
|
||||
const Y = D * 365;
|
||||
const Dec = Y * 10;
|
||||
const Sen = Y * 100;
|
||||
const divs = [H, D, M, Y, Dec, Sen];
|
||||
const startMediaTime = this.filterService.prefiltered.media.reduce((p, c) => p.metadata.creationDate < c.metadata.creationDate ? p : c).metadata.creationDate;
|
||||
|
||||
// finding the resolution
|
||||
let usedDiv = H;
|
||||
for (let i = 0; i < divs.length; ++i) {
|
||||
if (diff / divs[i] < 15) {
|
||||
usedDiv = divs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// getting the first date (truncated to the resolution)
|
||||
let startMediaDate = new Date(startMediaTime);
|
||||
if (usedDiv >= Y) {
|
||||
const fy = (new Date(startMediaTime).getFullYear());
|
||||
startMediaDate = new Date(fy - fy % (usedDiv / Y), 0, 1);
|
||||
} else if (usedDiv === M) {
|
||||
startMediaDate = new Date(startMediaDate.getFullYear(), startMediaDate.getMonth(), 1);
|
||||
} else {
|
||||
startMediaDate = new Date(startMediaTime - startMediaTime % usedDiv);
|
||||
}
|
||||
|
||||
this.filterService.prefiltered.media.forEach(m => {
|
||||
const key = Math.floor((m.metadata.creationDate - startMediaTime) / 1000 / usedDiv);
|
||||
|
||||
const getDate = (index: number) => {
|
||||
let d: Date;
|
||||
if (usedDiv >= Y) {
|
||||
d = new Date(startMediaDate.getFullYear() + (index * (usedDiv / Y)), 0, 1);
|
||||
} else if (usedDiv === M) {
|
||||
d = new Date(startMediaDate.getFullYear(), startMediaDate.getMonth() + index, 1);
|
||||
} else if (usedDiv === D) {
|
||||
d = new Date(startMediaDate.getFullYear(), startMediaDate.getMonth(), startMediaDate.getDate() + index, 1);
|
||||
} else {
|
||||
d = (new Date(startMediaDate.getTime() + (index * usedDiv * 1000)));
|
||||
}
|
||||
return d;
|
||||
};
|
||||
// extending the array
|
||||
while (ret.length <= key) {
|
||||
let dStr: string;
|
||||
// getting date range start for entry and also UI date pattern
|
||||
if (usedDiv >= Y) {
|
||||
dStr = 'yyyy';
|
||||
} else if (usedDiv === M) {
|
||||
dStr = 'MMM';
|
||||
} else if (usedDiv === D) {
|
||||
dStr = 'EEE';
|
||||
} else {
|
||||
dStr = 'HH';
|
||||
}
|
||||
ret.push({date: getDate(ret.length), endDate: getDate(ret.length + 1), dateStr: dStr, count: 0, max: 0});
|
||||
}
|
||||
|
||||
ret[key].count++;
|
||||
});
|
||||
|
||||
// don't show if there is only one column
|
||||
if (ret.length <= 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const max = ret.reduce((p, c) => Math.max(p, c.count), 0);
|
||||
ret.forEach(v => v.max = max);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
setTimeout(() => this.filterService.setShowingFilters(false));
|
||||
|
@ -120,15 +120,110 @@ export class FilterService {
|
||||
},
|
||||
],
|
||||
});
|
||||
public prefiltered: DirectoryContent;
|
||||
public statistic: { date: Date; endDate: Date; dateStr: string; count: number; max: number; }[] = [];
|
||||
|
||||
private getStatistic(prefiltered: DirectoryContent): { date: Date, endDate: Date, dateStr: string, count: number, max: number }[] {
|
||||
if (!prefiltered ||
|
||||
!prefiltered.media ||
|
||||
prefiltered.media.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const ret: { date: Date, endDate: Date, dateStr: string, count: number, max: number }[] = [];
|
||||
const minDate = prefiltered.media.reduce(
|
||||
(p, curr) => Math.min(p, curr.metadata.creationDate),
|
||||
Number.MAX_VALUE - 1
|
||||
);
|
||||
const maxDate = prefiltered.media.reduce(
|
||||
(p, curr) => Math.max(p, curr.metadata.creationDate),
|
||||
Number.MIN_VALUE + 1
|
||||
);
|
||||
const diff = (maxDate - minDate) / 1000;
|
||||
const H = 60 * 60;
|
||||
const D = H * 24;
|
||||
const M = D * 30;
|
||||
const Y = D * 365;
|
||||
const Y2 = Y * 2;
|
||||
const Y5 = Y * 5;
|
||||
const Dec = Y * 10;
|
||||
const Sen = Y * 100;
|
||||
const divs = [H, D, M, Y, Y2, Y5, Dec, Sen];
|
||||
|
||||
// finding the resolution
|
||||
let usedDiv = H;
|
||||
for (let i = 0; i < divs.length; ++i) {
|
||||
if (diff / divs[i] < 26) {
|
||||
usedDiv = divs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// getting the first date (truncated to the resolution)
|
||||
const floorDate = (ts: number): number => {
|
||||
let d = new Date(ts);
|
||||
if (usedDiv >= Y) {
|
||||
const fy = (d.getFullYear());
|
||||
d = new Date(fy - fy % (usedDiv / Y), 0, 1);
|
||||
} else if (usedDiv === M) {
|
||||
d = new Date(d.getFullYear(), d.getMonth(), 1);
|
||||
} else {
|
||||
d = new Date(ts - ts % usedDiv);
|
||||
}
|
||||
return d.getTime();
|
||||
};
|
||||
|
||||
const startMediaDate = new Date(floorDate(minDate));
|
||||
|
||||
prefiltered.media.forEach(m => {
|
||||
const key = Math.floor((floorDate(m.metadata.creationDate) - startMediaDate.getTime()) / 1000 / usedDiv);
|
||||
|
||||
const getDate = (index: number) => {
|
||||
let d: Date;
|
||||
if (usedDiv >= Y) {
|
||||
d = new Date(startMediaDate.getFullYear() + (index * (usedDiv / Y)), 0, 1);
|
||||
} else if (usedDiv === M) {
|
||||
d = new Date(startMediaDate.getFullYear(), startMediaDate.getMonth() + index, 1);
|
||||
} else if (usedDiv === D) {
|
||||
d = new Date(startMediaDate.getFullYear(), startMediaDate.getMonth(), startMediaDate.getDate() + index, 1);
|
||||
} else {
|
||||
d = (new Date(startMediaDate.getTime() + (index * usedDiv * 1000)));
|
||||
}
|
||||
return d;
|
||||
};
|
||||
// extending the array
|
||||
while (ret.length <= key) {
|
||||
let dStr: string;
|
||||
// getting date range start for entry and also UI date pattern
|
||||
if (usedDiv >= Y) {
|
||||
dStr = 'y';
|
||||
} else if (usedDiv === M) {
|
||||
dStr = 'y MMM';
|
||||
} else if (usedDiv === D) {
|
||||
dStr = 'EEE';
|
||||
} else {
|
||||
dStr = 'HH';
|
||||
}
|
||||
ret.push({date: getDate(ret.length), endDate: getDate(ret.length + 1), dateStr: dStr, count: 0, max: 0});
|
||||
}
|
||||
|
||||
ret[key].count++;
|
||||
});
|
||||
|
||||
// don't show if there is only one column
|
||||
if (ret.length <= 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const max = ret.reduce((p, c) => Math.max(p, c.count), 0);
|
||||
ret.forEach(v => v.max = max);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public applyFilters(
|
||||
directoryContent: Observable<DirectoryContent>
|
||||
): Observable<DirectoryContent> {
|
||||
return directoryContent.pipe(
|
||||
switchMap((dirContent: DirectoryContent) => {
|
||||
this.prefiltered = dirContent;
|
||||
this.statistic = this.getStatistic(dirContent);
|
||||
this.resetFilters(false);
|
||||
return this.activeFilters.pipe(
|
||||
map((afilters) => {
|
||||
|
Loading…
Reference in New Issue
Block a user