Issue #1190: Redesign of intro page

* Add an Activity graph for activity peaks
 * Add a storage graph for storage repartition
 * Redesign intro page for those charts
This commit is contained in:
Zacharie
2020-05-29 17:43:13 +02:00
committed by plegall
parent 67647080ea
commit 2633042618
4 changed files with 470 additions and 7 deletions

View File

@@ -187,6 +187,199 @@ SELECT MIN(date_available)
trigger_notify('loc_end_intro');
// +-----------------------------------------------------------------------+
// | get activity data |
// +-----------------------------------------------------------------------+
$number_week = 4;
$date = new DateTime();
//Array for the JS tooltip
$activity_last_weeks = array();
//Count mondays
$mondays = 0;
//Get mondays date (day + month) for the chart legend
$mondays_date = array();
//Array for sorting days in circle size
$temp_data = array();
//Get data from $number_week last weeks
while ($mondays < $number_week)
{
$date_string = $date->format('Y-m-d');
$query = '
SELECT *
FROM `'.ACTIVITY_TABLE.'`
WHERE occured_on LIKE "'.$date_string.'%"
;';
$result = query2array($query, null);
$this_day = array('number' => 0);
foreach ($result as $act) {
if(isset($this_day['details'][ucfirst($act['object'])][ucfirst($act['action'])]))
{
$this_day['details'][ucfirst($act['object'])][ucfirst($act['action'])] += 1;
} else {
$this_day['details'][ucfirst($act['object'])][ucfirst($act['action'])] = 1;
}
$this_day['number'] += 1;
}
if ($this_day['number'] > 0)
{
$temp_data[] = array('x' => $this_day['number'], 'd'=>$date->format('N'), 'w'=>$mondays);
}
$activity_last_weeks[$mondays][intval($date->format('N'))] = $this_day;
if ($date->format('D') == 'Mon') {
$mondays_date[$mondays]['m'] = $date->format('m');
$mondays_date[$mondays]['d'] = $date->format('d');
$mondays += 1;
}
$date->sub(new DateInterval('P1D'));
}
// Algorithm to sort days in circle size :
// * Get the difference between sorted numbers of activity per day (only not null numbers)
// * Split days max $circle_sizes time on the biggest difference (but not below 120%)
// * Set the sizes according to the groups created
//Function to sort days by number of activity
function cmp_day($a, $b)
{
if ($a['x'] == $b['x']) {
return 0;
}
return ($a['x'] < $b['x']) ? -1 : 1;
}
usort($temp_data, 'cmp_day');
//Get the percent difference
$diff_x = array();
for ($i=1; $i < count($temp_data); $i++)
{
$diff_x[] = $temp_data[$i]['x']/$temp_data[$i-1]['x']*100;
}
$split = 0;
//Split (split represented by -1)
while (max($diff_x) > 120) {
$diff_x[array_search(max($diff_x), $diff_x)] = -1;
$split++;
}
//Fill empty chart data for the template
$chart_data = array();
for ($i=0; $i < $number_week; $i++) {
for ($j=1; $j <= 7; $j++) {
$chart_data[$i][$j] = 0;
}
}
$size = 1;
$chart_data[$temp_data[0]['w']][$temp_data[0]['d']] = $size;
//Set sizes in chart data
for ($i=1; $i < count($temp_data); $i++) {
if ($diff_x[$i-1] == -1) {$size++;}
$chart_data[$temp_data[$i]['w']][$temp_data[$i]['d']] = $size;
}
//Assign data for the template
$template->assign('ACTIVITY_MONDAYS_DATE',array_reverse($mondays_date));
$template->assign('ACTIVITY_LAST_WEEKS', array_reverse($activity_last_weeks));
$template->assign('ACTIVITY_CHART_DATA',array_reverse($chart_data));
$template->assign('ACTIVITY_CHART_NUMBER_SIZES',$size);
// +-----------------------------------------------------------------------+
// | get storage data |
// +-----------------------------------------------------------------------+
$video_format = array('webm','webmv','ogg','ogv','mp4','m4v');
$data_storage = array();
//Select files in Image_Table
$query = '
SELECT file, filesize
FROM `'.IMAGES_TABLE.'`
;';
$result = query2array($query, null);
foreach ($result as $file)
{
$tabString = explode('.',$file['file']);
$ext = $tabString[count($tabString) -1];
$size = $file['filesize'];
if (in_array($ext, $conf['picture_ext']))
{
if (isset($data_storage['Photos']))
{
$data_storage['Photos'] += $size;
} else {
$data_storage['Photos'] = $size;
}
} elseif (in_array($ext, $video_format)) {
if (isset($data_storage['Videos']))
{
$data_storage['Videos'] += $size;
} else {
$data_storage['Videos'] = $size;
}
} else {
if (isset($data_storage['Others']))
{
$data_storage['Others'] += $size;
} else {
$data_storage['Others'] = $size;
}
}
}
//Select files from format table
$query = '
SELECT SUM(filesize)
FROM `'.IMAGE_FORMAT_TABLE.'`
;';
$result = query2array($query);
if (isset($result[0]['SUM(filesize)']))
{
$data_storage['Format'] = $result[0]['SUM(filesize)'];
}
//If the host is not windows, get the cache size
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
{
$f = './_data';
$io = popen ( '/usr/bin/du -sk ' . $f, 'r' );
$size = fgets ($io, 4096);
$size = substr ( $size, 0, strpos ( $size, "\t" ) );
pclose ( $io );
$data_storage['Cache'] = $size;
}
//Calculate total storage
$total_storage = 0;
foreach ($data_storage as $value)
{
$total_storage += $value;
}
//Get percentage of the total storage
foreach ($data_storage as $key=>$value)
{
$data_storage[$key] = $value/$total_storage*100;
}
//Pass data to HTML
$template->assign('STORAGE_TOTAL',$total_storage/1000);
$template->assign('STORAGE_CHART_DATA',$data_storage);
// +-----------------------------------------------------------------------+
// | sending html code |
// +-----------------------------------------------------------------------+

View File

@@ -7,7 +7,7 @@ var piwigo_need_update_msg = '<a href="admin.php?page=updates">{'A new version o
var ext_need_update_msg = '<a href="admin.php?page=updates&amp;tab=ext">{'Some upgrades are available for extensions.'|@translate|@escape:"javascript"} <i class="icon-right"></i></a>';
{literal}
jQuery().ready(function(){
jQuery().ready(function(){
jQuery('.cluetip').cluetip({
width: 300,
splitTitle: '|',
@@ -61,6 +61,7 @@ jQuery().ready(function(){
<h2>{'Piwigo Administration'|@translate}</h2>
<div class="intro-page-container">
<div class="stat-boxes">
{if $NB_PHOTOS > 1}
@@ -140,6 +141,52 @@ jQuery().ready(function(){
</div> {* .stat-boxes *}
<div class="intro-charts">
<div class="chart-title"> {"Activity peak in the last weeks"|@translate}</div>
<div class="activity-chart" style="grid-template-rows: repeat({count($ACTIVITY_CHART_DATA) + 1}, 6vw);">
{foreach from=$ACTIVITY_CHART_DATA item=WEEK_ACTIVITY key=WEEK_NUMBER}
<div id="week-{$WEEK_NUMBER}-legend" class="row-legend"><div>{"Week of %s/%s"|@translate:$ACTIVITY_MONDAYS_DATE[$WEEK_NUMBER]['d']:$ACTIVITY_MONDAYS_DATE[$WEEK_NUMBER]['m']}</div></div>
{foreach from=$WEEK_ACTIVITY item=SIZE key=DAY_NUMBER}
<span>
{if $SIZE != 0}
<div id="day{$WEEK_NUMBER}-{$DAY_NUMBER}" style="height:{$SIZE/$ACTIVITY_CHART_NUMBER_SIZES * 7 + 1}vw;width:{$SIZE/$ACTIVITY_CHART_NUMBER_SIZES * 7 + 1}vw;opacity:{$SIZE/$ACTIVITY_CHART_NUMBER_SIZES * 0.7 + 0.1}"></div>
{if $ACTIVITY_LAST_WEEKS[$WEEK_NUMBER][$DAY_NUMBER]["number"] != 0}
<p style="transform: translate(-50%, 50%) translate(0, {if $SIZE/2 >= 1}{$SIZE/2}{else}2{/if}vw)">
<b>{"%s Activities"|@translate:$ACTIVITY_LAST_WEEKS[$WEEK_NUMBER][$DAY_NUMBER]["number"]}</b>
{foreach from=$ACTIVITY_LAST_WEEKS[$WEEK_NUMBER][$DAY_NUMBER]["details"] item=actions key=cat}
<br> {$cat} : {foreach from=$actions item=number key=action} ({$action}) {$number} {/foreach}
{/foreach}
</p>
{/if}
{/if}
</span>
{/foreach}
{/foreach}
<div></div>
{foreach from=array('Mon'|translate, 'Tue'|translate, 'Wed'|translate, 'Thu'|translate, 'Fri'|translate, 'Sat'|translate, 'Sun'|translate) item=day}
<div class="col-legend">{$day} <div class="line-vertical" style="height: {count($ACTIVITY_CHART_DATA)*100 - 50}%;"></div></div>
{/foreach}
</div>
<div class="chart-title"> {"Storage"|@translate} <span class="chart-title-infos"> {'%s MB used'|translate:$STORAGE_TOTAL} </span></div>
<div class="storage-chart">
{foreach from=$STORAGE_CHART_DATA item=value}
<span style="width:{$value}%"> <p>{round($value)}%</p> </span>
{/foreach}
</div>
<div class="storage-chart-legend">
{foreach from=$STORAGE_CHART_DATA item=i key=type}
<div><span></span> <p>{$type|translate}</p></div>
{/foreach}
</div>
</div> {* .intro-chart *}
</div> {* .intro-page-container *}
<p class="showCreateAlbum">
{if $ENABLE_SYNCHRONIZATION}
<a href="{$U_QUICK_SYNC}" class="icon-exchange">{'Quick Local Synchronization'|translate}</a>
@@ -149,4 +196,4 @@ jQuery().ready(function(){
{if isset($SUBSCRIBE_BASE_URL)}
<br><span class="newsletter-subscription"><a href="{$SUBSCRIBE_BASE_URL}{$EMAIL}" id="newsletterSubscribe" class="externalLink cluetip icon-mail-alt" title="{'Piwigo Announcements Newsletter'|@translate}|{'Keep in touch with Piwigo project, subscribe to Piwigo Announcement Newsletter. You will receive emails when a new release is available (sometimes including a security bug fix, it\'s important to know and upgrade) and when major events happen to the project. Only a few emails a year.'|@translate|@htmlspecialchars|@nl2br}">{'Subscribe %s to Piwigo Announcements Newsletter'|@translate:$EMAIL}</a> <a href="#" class="newsletter-hide">{'... or hide this link'|translate}</a></span>
{/if}
</p>
</p>

View File

@@ -545,14 +545,18 @@ FORM.properties SPAN.property {
}
/* Dashboard */
.intro-page-container {
display: grid;
grid-template-columns: 41% 44%;
}
.stat-boxes {
text-align:left;
margin:40px 10px;
text-align:center;
}
.stat-box {
display:inline-block;
width:200px;
width:150px;
margin:10px 10px 40px 10px;
color:#3b3b3b;
text-align: center;
@@ -565,7 +569,7 @@ div.stat-box {
.stat-box i {
display: inline-block;
border-radius: 50%;
font-size: 37px;
font-size: 30px;
padding: 20px;
margin-bottom: 15px;
}
@@ -586,6 +590,212 @@ a.stat-box:hover {
color:#777;
}
.intro-charts {
width: 48vw;
}
.chart-title {
font-size: 18px;
text-align: left;
font-weight: bold;
margin-bottom: 20px;
color: #3b3b3b;
position: relative;
}
.chart-title-infos {
font-size: 14px;
position: absolute;
right: 0;
bottom: 0;
}
.activity-chart {
font-weight: bold;
font-size: 14px;
display: grid;
grid-template-columns: repeat(8, 6vw) ;
grid-template-rows: repeat(4, 6vw);
}
.activity-chart .row-legend,.activity-chart .col-legend {
position: relative;
}
.activity-chart .row-legend {
display: flex;
}
.activity-chart .row-legend div{
margin: auto;
}
.activity-chart .col-legend {
line-height: 6vw;
}
.activity-chart .row-legend:after {
content: "";
border-top: 2px solid black;
opacity: 0.05;
position: absolute;
width: 700%;
transform: translate(6vw,3vw);
}
.activity-chart .col-legend .line-vertical {
border-left: 2px solid black;
opacity: 0.05;
position: absolute;
height: 250%;
left: 50%;
bottom: 100%;
}
.activity-chart span {
display: flex;
overflow: visible;
position: relative;
}
.activity-chart span div{
height: 0px;
width: 0px;
background-color: #ff5252;
opacity: 0.8;
display: block;
border-radius: 100%;
z-index: 100;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.activity-chart span p {
position: absolute;
display: none;
opacity: 0;
z-index: 102;
font-size: 12px;
font-weight: normal;
background-color: white;
padding: 5px;
width: 150px;
box-shadow: 0px 0px 5px #acacac;
border-radius: 5px;
transform : translate(-50%, 5vw);
transition: ease 0.2s;
left: 50%;
}
.activity-chart span p::after {
content: " ";
position: absolute;
bottom: 100%; /* At the bottom of the tooltip */
left: 51%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent white transparent;
}
.activity-chart span div:hover{
padding: 0.5vw;
}
.activity-chart span div:hover + p{
display: block;
opacity: 1;
}
.activity-chart #week-1-legend ~ span div {
background-color: #2883c3;
}
.activity-chart #week-2-legend ~ span div {
background-color: #896af3 ;
}
.activity-chart #week-3-legend ~ span div {
background-color: #6ece5e ;
}
.activity-chart #week-4-legend ~ span div {
background-color: #ffa744 ;
}
.storage-chart {
border-radius: 5px;
width: 100%;
overflow: hidden;
position: relative;
height: 30px;
display: flex;
background-color: #e8e8e8;
}
.storage-chart span{
opacity: 0.7;
transition: ease 0.2s;
}
.storage-chart span p{
font-weight: bold;
font-size: 16px;
color: black;
opacity: 0;
line-height: 0;
transition: ease 0.2s;
}
.storage-chart span:hover{
opacity: 1;
}
.storage-chart span:hover p{
opacity: 0.4;
}
.storage-chart-legend {
display: flex
}
.storage-chart-legend div{
padding: 10px;
display: flex;
align-items: center;
font-size: 14px;
}
.storage-chart-legend div span{
width: 15px;
height: 15px;
display: block;
margin: 5px;
opacity: 0.7;
}
.storage-chart span:nth-child(1), .storage-chart-legend div:nth-child(1) span{
background-color:#ffa744;
}
.storage-chart span:nth-child(2), .storage-chart-legend div:nth-child(2) span{
background-color:#6ece5e;
}
.storage-chart span:nth-child(3), .storage-chart-legend div:nth-child(3) span{
background-color:#896af3;
}
.storage-chart span:nth-child(4), .storage-chart-legend div:nth-child(4) span{
background-color:#2883c3;
}
.storage-chart span:nth-child(5), .storage-chart-legend div:nth-child(5) span{
background-color:#ff5252;
}
#configContent fieldset {
border:none;
padding-left:20px;

View File

@@ -232,6 +232,19 @@ a.stat-box:hover {
background-color: #555
}
.chart-title {
color: #777;
}
.activity-chart span p {
background-color: #333333;
box-shadow: none;
}
.activity-chart span p::after {
border-color: transparent transparent #333333 transparent;
}
/* hacks */
* html[lang="en"] body .content h2 , *+html[lang="en"] body .content h2 { text-transform:capitalize; } /* IE */
*+html .bigtext { left: 70px; }
@@ -876,4 +889,4 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
.icon-green {
background-color: #4ac641;
color: #014400;
}
}