Skip to content

Commit

Permalink
Add Charts API
Browse files Browse the repository at this point in the history
  • Loading branch information
MrMicky-FR committed Aug 16, 2020
1 parent d6f403f commit 5e11a93
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 227 deletions.
49 changes: 3 additions & 46 deletions app/Http/Controllers/Admin/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Azuriom\Models\Page;
use Azuriom\Models\Post;
use Azuriom\Models\User;
use Azuriom\Support\Charts;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\Request;

Expand Down Expand Up @@ -41,8 +42,8 @@ public function index(Request $request)
'postCount' => Post::count(),
'pageCount' => Page::count(),
'imageCount' => Image::count(),
'recentUsers' => $this->getRecentUsers(),
'recentUsersWeek' => $this->getRecentUsersWeek(),
'newUsersPerMonths' => Charts::countByMonths(User::query()),
'newUsersPerDays' => Charts::countByDays(User::query()),
'activeUsers' => $this->getActiveUsers(),
'newVersion' => $newVersion,
'apiAlerts' => $updates->getApiAlerts(),
Expand All @@ -54,50 +55,6 @@ public function fallback()
return response()->view('admin.errors.404', [], 404);
}

protected function getRecentUsers()
{
$date = now()->subMonths(6);
$recentUsers = [];

$queryUsers = User::where('created_at', '>=', $date)
->without('role')
->get(['id', 'created_at'])
->countBy(function ($user) {
return $user->created_at->translatedFormat('M Y');
});

for ($i = 0; $i < 6; $i++) {
$date->addMonth();
$time = $date->translatedFormat('M Y');

$recentUsers[$time] = $queryUsers->get($time, 0);
}

return collect($recentUsers);
}

protected function getRecentUsersWeek()
{
$date = now()->subDays(6);
$recentUsers = [];

$queryUsers = User::where('created_at', '>=', $date)
->without('role')
->get(['id', 'created_at'])
->countBy(function ($user) {
return $user->created_at->translatedFormat('D M');
});

for ($i = 0; $i < 6; $i++) {
$date->addDay();
$time = $date->translatedFormat('D M');

$recentUsers[$time] = $queryUsers->get($time, 0);
}

return collect($recentUsers);
}

protected function getActiveUsers()
{
$days = [1, 7, 31];
Expand Down
121 changes: 121 additions & 0 deletions app/Support/Charts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace Azuriom\Support;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class Charts
{
public static function count(Builder $query, string $column)
{
return static::aggregate($query, __FUNCTION__, '*', $column);
}

public static function sum(Builder $query, string $column, string $group)
{
return static::aggregate($query, __FUNCTION__, $column, $group);
}

public static function aggregate(Builder $query, string $function, string $column, string $group)
{
return $query->select($group, DB::raw("{$function}({$query->getGrammar()->wrap($column)}) as aggregate"))
->groupBy($group)
->get()
->pluck('aggregate', $group);
}

public static function countByDays(Builder $query, string $column = 'created_at', int $days = 7)
{
return static::aggregateByDays($query, 'count', $column, $days);
}

public static function sumByDays(Builder $query, string $column = 'created_at', int $days = 7)
{
return static::aggregateByDays($query, 'sum', $column, $days);
}

public static function aggregateByDays(Builder $query, string $function, string $column = null, int $days = 7)
{
$start = today()->subDays($days);
$date = $start->clone();
$dates = collect();
$column = $column ?? 'created_at';

while ($date->isPast() || $date->isToday()) {
$dates->put(format_date($date), 0);

$date = $date->addDay();
}

$results = $query->select(DB::raw("date({$query->getGrammar()->wrap($column)}) as date, {$function}(*) as aggregate"))
->where($column, '>', $start)
->groupBy('date')
->orderBy('date')
->get()
->mapWithKeys(function ($value) {
$date = Carbon::createFromFormat('Y-m-d', $value->date);

return [format_date($date) => $value->aggregate];
});

return $dates->merge($results);
}

public static function countByMonths(Builder $query, string $column = null, int $months = 12)
{
return static::aggregateByMonths($query, 'count', $column, $months);
}

public static function sumByMonths(Builder $query, string $column = null, int $months = 12)
{
return static::aggregateByMonths($query, 'sum', $column, $months);
}

public static function aggregateByMonths(Builder $query, string $function, string $column = null, int $months = 12)
{
$start = now()->startOfMonth()->subMonths($months - 1);
$date = $start->clone();
$dates = collect();
$column = $column ?? 'created_at';

while ($date->isPast()) {
$dates->put($date->translatedFormat('F Y'), 0);

$date = $date->addMonth();
}

$rawQuery = static::getDatabaseRawQuery($query, $query->getGrammar()->wrap($column));

$results = $query->select(DB::raw("{$rawQuery} as date, {$function}(*) as aggregate"))
->where($column, '>', $start)
->groupBy('date')
->orderBy('date')
->get()
->mapWithKeys(function ($result) {
$date = Carbon::createFromFormat('Y-m', $result->date);

return [$date->translatedFormat('F Y') => $result->aggregate];
});

return $dates->merge($results);
}

protected static function getDatabaseRawQuery(Builder $query, string $column)
{
$driver = $query->getConnection()->getDriverName();

switch ($driver) {
case 'mysql':
return "date_format({$column}, '%Y-%m')";
case 'sqlite':
return "strftime('%Y-%m', {$column})";
case 'pgsql':
return "to_char({$column}, 'YYYY-MM')";
default:
throw new RuntimeException('Unsupported database driver: '.$driver);
}
}
}
109 changes: 109 additions & 0 deletions public/assets/admin/js/charts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
function createLineChart(elementId, data, labelName) {
Chart.defaults.global.defaultFontFamily = 'Nunito';
Chart.defaults.global.defaultFontColor = '#858796';

new Chart(document.getElementById(elementId), {
type: 'line',
data: {
labels: Object.keys(data),
datasets: [{
label: labelName,
lineTension: 0.3,
backgroundColor: "rgba(78, 115, 223, 0.05)",
borderColor: "rgba(78, 115, 223, 1)",
pointRadius: 3,
pointBackgroundColor: "rgba(78, 115, 223, 1)",
pointBorderColor: "rgba(78, 115, 223, 1)",
pointHoverRadius: 3,
pointHoverBackgroundColor: "rgba(78, 115, 223, 1)",
pointHoverBorderColor: "rgba(78, 115, 223, 1)",
pointHitRadius: 10,
pointBorderWidth: 2,
data: Object.values(data),
}],
},
options: {
maintainAspectRatio: false,
scales: {
xAxes: [{
time: {
unit: 'date'
},
gridLines: {
display: false,
drawBorder: false
},
ticks: {
maxTicksLimit: 7
},
}],
yAxes: [{
ticks: {
maxTicksLimit: 5,
padding: 10,
},
gridLines: {
color: "rgb(234, 236, 244)",
zeroLineColor: "rgb(234, 236, 244)",
drawBorder: false,
borderDash: [2],
zeroLineBorderDash: [2],
},
}],
},
legend: {
display: false
},
tooltips: {
backgroundColor: "rgb(255,255,255)",
bodyFontColor: "#858796",
titleMarginBottom: 10,
titleFontColor: '#6e707e',
titleFontSize: 14,
borderColor: '#dddfeb',
borderWidth: 1,
xPadding: 15,
yPadding: 15,
displayColors: false,
intersect: false,
mode: 'index',
caretPadding: 10,
}
}
});
}

function createPieChart(elementId, data) {
Chart.defaults.global.defaultFontFamily = 'Nunito';
Chart.defaults.global.defaultFontColor = '#858796';

new Chart(document.getElementById('activeUsersChart'), {
type: 'doughnut',
data: {
labels: Object.keys(data),
datasets: [{
data: Object.values(data),
backgroundColor: ['#4e73df', '#1cc88a', '#36b9cc', '#e9aa0b'],
hoverBackgroundColor: ['#2e59d9', '#17a673', '#2c9faf', '#f4b619'],
hoverBorderColor: 'rgba(234, 236, 244, 1)',
}],
},
options: {
maintainAspectRatio: false,
tooltips: {
backgroundColor: '#fff',
bodyFontColor: '#858796',
borderColor: '#dddfeb',
borderWidth: 1,
xPadding: 15,
yPadding: 15,
displayColors: false,
caretPadding: 10,
},
legend: {
display: false,
},
cutoutPercentage: 60,
},
});
}

0 comments on commit 5e11a93

Please sign in to comment.