diff --git a/app/Http/Controllers/Gallery/StatisticsController.php b/app/Http/Controllers/Gallery/StatisticsController.php new file mode 100644 index 0000000..94cb87f --- /dev/null +++ b/app/Http/Controllers/Gallery/StatisticsController.php @@ -0,0 +1,230 @@ +join('albums', 'albums.id', '=', 'photos.album_id') + ->groupBy('albums.name') + ->select('albums.name', DB::raw('count(photos.id) as photo_count')) + ->orderBy('photo_count', 'desc') + ->limit(10) + ->get(); + + $labels = []; + $data = []; + + foreach ($stats as $stat) + { + $labels[] = $stat->name; + $data[] = $stat->photo_count; + } + + return response()->json([ + 'labels' => $labels, + 'backgrounds' => $this->rotateColoursForData($data), + 'data' => $data + ]); + } + + public function albumSizeByPhotoSizeChart(Request $request) + { + $stats = DB::table('photos') + ->join('albums', 'albums.id', '=', 'photos.album_id') + ->groupBy('albums.name') + ->select('albums.name', DB::raw('sum(photos.file_size) as photo_size')) + ->orderBy('photo_size', 'desc') + ->limit(10) + ->get(); + + $labels = []; + $data = []; + + foreach ($stats as $stat) + { + $labels[] = $stat->name; + $data[] = ceil($stat->photo_size / 1024 / 1024); + } + + return response()->json([ + 'labels' => $labels, + 'backgrounds' => $this->rotateColoursForData($data), + 'data' => $data + ]); + } + + public function camerasChart(Request $request) + { + $stats = DB::table('photos') + ->where([ + ['camera_make', '!=', ''], + ['camera_model', '!=', ''] + ]) + ->groupBy('camera_make', 'camera_model') + ->select('camera_make', 'camera_model', DB::raw('count(*) as photo_count')) + ->orderBy('photo_count', 'desc') + ->get(); + + $labels = []; + $data = []; + + foreach ($stats as $stat) + { + // Remove the model from the make if it starts with it + // E.g. CANON - CANON EOS 1200D becomes just CANON EOS 1200D + if (substr($stat->camera_model, 0, strlen($stat->camera_make)) == $stat->camera_make) + { + $stat->camera_make = trim(substr($stat->camera_make, strlen($stat->camera_make))); + } + + $labels[] = sprintf('%s %s', $stat->camera_make, $stat->camera_model); + $data[] = $stat->photo_count; + } + + return response()->json([ + 'labels' => $labels, + 'backgrounds' => $this->rotateColoursForData($data), + 'data' => $data + ]); + } + + public function fileSizeChart(Request $request) + { + $labels = [ + trans('gallery.statistics.file_sizes_legend.small'), + trans('gallery.statistics.file_sizes_legend.medium'), + trans('gallery.statistics.file_sizes_legend.large'), + trans('gallery.statistics.file_sizes_legend.huge') + ]; + $data = [0, 0, 0, 0]; + + $stats = DB::table('photos'); + $stats->chunk(100, function($photos) use (&$data) + { + foreach ($photos as $photo) + { + if ($photo->file_size < (1 * 1024 * 1024)) + { + $data[0]++; + } + else if ($photo->file_size < (3 * 1024 * 1024)) + { + $data[1]++; + } + else if ($photo->file_size < (5 * 1024 * 1024)) + { + $data[2]++; + } + else if ($photo->file_size >= (5 * 1024 * 1024)) + { + $data[3]++; + } + } + }); + + return response()->json([ + 'labels' => $labels, + 'backgrounds' => $this->rotateColoursForData($data), + 'data' => $data + ]); + } + + public function index(Request $request) + { + return Theme::render('gallery.statistics'); + } + + public function photosTaken12Months(Request $request) + { + $labels = []; + $data = []; + + foreach ($this->last12MonthsDates() as $date) + { + $fromDate = sprintf('%04d-%02d-01 00:00:00', $date[0], $date[1]); + $toDate = sprintf('%04d-%02d-%02d 23:59:59', $date[0], $date[1], cal_days_in_month(CAL_GREGORIAN, $date[1], $date[0])); + + $photoCount = Photo::whereBetween('taken_at', array($fromDate, $toDate))->count(); + + $labels[] = date('M Y', strtotime($fromDate)); + $data[] = $photoCount; + } + + return response()->json([ + 'labels' => array_reverse($labels), + 'data' => array_reverse($data) + ]); + } + + public function photosUploaded12Months(Request $request) + { + $labels = []; + $data = []; + + foreach ($this->last12MonthsDates() as $date) + { + $fromDate = sprintf('%04d-%02d-01 00:00:00', $date[0], $date[1]); + $toDate = sprintf('%04d-%02d-%02d 23:59:59', $date[0], $date[1], cal_days_in_month(CAL_GREGORIAN, $date[1], $date[0])); + + $photoCount = Photo::whereBetween('created_at', array($fromDate, $toDate))->count(); + + $labels[] = date('M Y', strtotime($fromDate)); + $data[] = $photoCount; + } + + return response()->json([ + 'labels' => array_reverse($labels), + 'data' => array_reverse($data) + ]); + } + + private function last12MonthsDates() + { + $year = intval(date('Y')); + $month = intval(date('m')); + + $datesNeeded = []; + + while (count($datesNeeded) < 12) + { + $datesNeeded[] = [$year, $month]; + + $month--; + if ($month == 0) + { + $month = 12; + $year--; + } + } + + return $datesNeeded; + } + + private function rotateColoursForData(array $data = []) + { + $colours = ['#0F2240', '#174E79', '#287598', '#46BBB5', '#35DCAD']; + $result = []; + $lastIndex = 0; + + for ($i = 0; $i < count($data); $i++) + { + $result[] = $colours[$lastIndex]; + $lastIndex++; + if ($lastIndex >= count($colours)) + { + $lastIndex = 0; + } + } + + return $result; + } +} \ No newline at end of file diff --git a/resources/lang/en/gallery.php b/resources/lang/en/gallery.php index 3701e02..9e1453f 100644 --- a/resources/lang/en/gallery.php +++ b/resources/lang/en/gallery.php @@ -14,5 +14,21 @@ return [ 'manage_album_link_2' => 'Manage Album', 'open_album_link' => 'Open Album', 'other_albums_description' => 'You may also be interested in the following albums.', - 'other_albums_heading' => 'More Albums in :album_name' + 'other_albums_heading' => 'More Albums in :album_name', + 'statistics' => [ + 'album_by_photos' => 'Top 10 largest albums - number of photos', + 'album_by_size' => 'Top 10 largest albums - photo size (MB)', + 'cameras' => 'Cameras Used', + 'file_sizes' => 'Image file sizes', + 'file_sizes_legend' => [ + 'small' => 'Small (<1MB)', + 'medium' => 'Medium (<3MB)', + 'large' => 'Large (<5MB)', + 'huge' => 'Huge (>5MB)' + ], + 'intro' => 'This page displays some interesting graphs and statistics about :gallery_name.', + 'taken_12_months' => 'Photos taken in the last 12 months', + 'title' => 'Statistics', + 'uploaded_12_months' => 'Photos uploaded in the last 12 months', + ] ]; \ No newline at end of file diff --git a/resources/lang/en/navigation.php b/resources/lang/en/navigation.php index a6cbc24..a3af3ed 100644 --- a/resources/lang/en/navigation.php +++ b/resources/lang/en/navigation.php @@ -27,6 +27,7 @@ return [ 'change_password' => 'Change password', 'login' => 'Login', 'logout' => 'Logout', - 'register' => 'Register' + 'register' => 'Register', + 'statistics' => 'Statistics' ] ]; \ No newline at end of file diff --git a/resources/views/themes/base/gallery/statistics.blade.php b/resources/views/themes/base/gallery/statistics.blade.php new file mode 100644 index 0000000..5db20be --- /dev/null +++ b/resources/views/themes/base/gallery/statistics.blade.php @@ -0,0 +1,250 @@ +@extends('themes.base.layout') +@section('title', trans('gallery.statistics.title')) + +@section('breadcrumb') + + +@endsection + +@section('content') +
+
+
+

@lang('gallery.statistics.title')

+
+ @lang('gallery.statistics.intro', ['gallery_name' => UserConfig::get('app_name')]) +
+
+
+ +
+
+
+
@lang('gallery.statistics.taken_12_months')
+
+ + +
+
+
+ +
+
+
@lang('gallery.statistics.uploaded_12_months')
+
+ + +
+
+
+
+ +
+
+
+
@lang('gallery.statistics.cameras')
+
+ + +
+
+
+ +
+
+
@lang('gallery.statistics.file_sizes')
+
+ + +
+
+
+
+ +
+
+
+
@lang('gallery.statistics.album_by_photos')
+
+ + +
+
+
+ +
+
+
@lang('gallery.statistics.album_by_size')
+
+ + +
+
+
+
+
+@endsection + +@push('scripts') + {{-- TODO: include ChartJS locally --}} + + +@endpush \ No newline at end of file diff --git a/resources/views/themes/base/partials/navbar.blade.php b/resources/views/themes/base/partials/navbar.blade.php index 66bf6a9..43e42c0 100644 --- a/resources/views/themes/base/partials/navbar.blade.php +++ b/resources/views/themes/base/partials/navbar.blade.php @@ -9,7 +9,7 @@ @if (count($albums) > 0) + @endif @if (!Auth::guest() && (Auth::user()->can('admin:access'))) diff --git a/routes/web.php b/routes/web.php index 9a138c6..851f156 100644 --- a/routes/web.php +++ b/routes/web.php @@ -69,6 +69,13 @@ Route::get('/activate/{token}', 'Auth\ActivateController@activate')->name('auth. Route::get('/password/change', 'Auth\ChangePasswordController@showChangePasswordForm')->name('auth.changePassword'); Route::post('/password/change', 'Auth\ChangePasswordController@processChangePassword')->name('auth.processChangePassword'); Route::get('/sitemap.xml', 'Gallery\DefaultController@sitemapXml'); +Route::get('/statistics', 'Gallery\StatisticsController@index')->name('statistics.index'); +Route::get('/statistics/album-size-photo-count', 'Gallery\StatisticsController@albumSizeByPhotosChart')->name('statistics.albumSizePhotos'); +Route::get('/statistics/album-size-photo-size', 'Gallery\StatisticsController@albumSizeByPhotoSizeChart')->name('statistics.albumSizePhotoSize'); +Route::get('/statistics/cameras', 'Gallery\StatisticsController@camerasChart')->name('statistics.cameras'); +Route::get('/statistics/file-sizes', 'Gallery\StatisticsController@fileSizeChart')->name('statistics.fileSizes'); +Route::get('/statistics/taken-12m', 'Gallery\StatisticsController@photosTaken12Months')->name('statistics.taken12Months'); +Route::get('/statistics/uploaded-12m', 'Gallery\StatisticsController@photosUploaded12Months')->name('statistics.uploaded12Months'); Route::get('a/{albumUrlAlias}', 'Gallery\AlbumController@index') ->name('viewAlbum') ->where('albumUrlAlias', '.*');