Implement pie chart

This commit is contained in:
Les De Ridder 2018-10-18 05:37:08 +02:00
parent 382ba5f87c
commit 86da4c2ec3
3 changed files with 84 additions and 103 deletions

View File

@ -5,8 +5,9 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Validator;
use DB;
use Cache;
use App\Poll;
use App\PollVote;
use App\PollVotingCode;
@ -94,14 +95,79 @@ class PollController extends Controller
{
$voted = $request->session()->pull('voted', false);
$this->createPieChart($poll);
return view('view_poll_results')
->with('poll', $poll)
->with('voted', $voted);
}
private static function createPieChart(Poll $poll)
private function createPieChart(Poll $poll)
{
//TODO
$voteCount = $poll->votes->count();
if(Cache::has($poll->id) && Cache::get($poll->id)['vote_count'] == $voteCount) {
return;
}
$baseColours = [[0xE8, 0x96, 0x3F], [0xAD, 0x3F, 0xE8], [0x3F, 0xE8, 0x6F], [0xE8, 0xE3, 0x3F], [0x3F, 0x64, 0xEB], [0xE8, 0x3F, 0x65], [0x3F, 0xE8, 0xDB]];
shuffle($baseColours);
$supersamplingFactor = 8;
$width = 512 * $supersamplingFactor;
$height = 512 * $supersamplingFactor;
$padding = 16 * $supersamplingFactor;
$chartWidth = $width - 2 * $padding;
$chartHeight = $height - 2 * $padding;
$pieChart = imagecreatetruecolor($width, $height);
imagefill($pieChart, 0, 0, imagecolorallocate($pieChart, 0xFF, 0xFF, 0xFF));
imageantialias($pieChart, true);
$primary = imagecolorallocate($pieChart, 0xE8, 0x3F, 0xB8);
$colours = [];
$startDegrees = 0;
$sortedOptions = $poll->options->sortByDesc(function($option) use($poll) { return $poll->votes->where('poll_option_id', $option->id)->count(); });
$nonZeroOptions = $sortedOptions->filter(function($option) use($poll) { return $poll->votes->where('poll_option_id', $option->id)->count() > 0; })->values();
debug($nonZeroOptions);
for($i = 0; $i < $poll->options->count(); $i++) {
$option = $nonZeroOptions[$i];
//TODO: Fix gaps
$degrees = round($poll->votes->where('poll_option_id', $option->id)->count() / $voteCount * 360);
$endDegrees = min($startDegrees + $degrees, 360);
$c = function($j) use($i, $baseColours, $nonZeroOptions) {
return $baseColours[$i % count($baseColours)][$j]
+ (255 - $baseColours[$i % count($baseColours)][$j])
* floor($i / count($baseColours)) / (floor($nonZeroOptions->count() / count($baseColours)) + 1);
};
$colour = imagecolorallocate($pieChart, $c(0), $c(1), $c(2));
$colours[$option->id] = '#' . dechex($c(0) << 16 | $c(1) << 8 | $c(2) << 0);
debug([$option->text, [$startDegrees, $endDegrees], [$c(0), $c(1), $c(2)]]);
imagefilledarc($pieChart, $width / 2, $height / 2, $chartWidth, $chartHeight, $startDegrees, $endDegrees, $colour, IMG_ARC_PIE);
$startDegrees = $endDegrees;
}
debug($colours);
$resized = imagecreatetruecolor($width / $supersamplingFactor, $height / $supersamplingFactor);
imagecopyresampled($resized, $pieChart, 0, 0, 0, 0, $width / $supersamplingFactor, $height / $supersamplingFactor, $width, $height);
$pieChart = $resized;
ob_start();
imagepng($pieChart);
$dataUri = "data:image/png;base64," . base64_encode(ob_get_contents());
ob_end_clean();
Cache::put($poll->id, ['vote_count' => $voteCount, 'pie_chart' => $dataUri, 'colours' => $colours], now()->addDays(1));
}
public function hasVoted(Request $request, Poll $poll)

View File

@ -10,12 +10,15 @@
@endif
@if($poll->results_visible)
@php ($sortedOptions = $poll->options->sortByDesc(function($option) use($poll) { return $poll->votes->where('poll_option_id', $option->id)->count(); }))
@php ($nonZeroOptions = $sortedOptions->filter(function($option) use($poll) { return $poll->votes->where('poll_option_id', $option->id)->count() > 0; }))
<section class="grid grid--large some-top-margin">
<div class="some-bottom-margin">
<div class="primary-box">
@php ($total = $poll->votes->count())
@foreach ($poll->options->sortByDesc(function($option) use($poll) { return $poll->votes->where('poll_option_id', $option->id)->count(); }) as $option)
@foreach ($sortedOptions as $option)
@php ($votes = $poll->votes->where('poll_option_id', $option->id)->count())
<div class="some-more-bottom-margin">
@ -24,6 +27,7 @@
<span style="float:right">{{ $votes }} votes</span>
</div>
<div>
<!-- TODO: title attribute -->
<div style="background-color:#e83fb8;height:2rem;width:{{ $votes / $total * 100 }}%;">
</div>
</div>
@ -36,8 +40,17 @@
</div>
</div>
<div>
@php ($cache = Cache::get($poll->id))
<div class="primary-box">
<span>TODO: Put a pie chart here.</span>
<img src="{{ $cache['pie_chart']}}" style="display:block;margin: 0 auto">
<br>
@foreach ($nonZeroOptions as $option)
<!-- TODO: Generate images so this works on text browsers -->
<div style="display:inline-block;height:1rem;width:1rem;background-color:{{$cache['colours'][$option->id]}};margin-right:1rem"></div>
<span>{{ $option->text }}</span>
<br>
@endforeach
</div>
</div>
</section>

View File

@ -1,98 +0,0 @@
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet" type="text/css">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 200;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 12px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@auth
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ route('login') }}">Login</a>
@if (Route::has('register'))
<a href="{{ route('register') }}">Register</a>
@endif
@endauth
</div>
@endif
<div class="content">
<div class="title m-b-md">
Laravel
</div>
<div class="links">
<a href="https://laravel.com/docs">Documentation</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>