mirror of
https://github.com/Piwigo/Piwigo.git
synced 2026-05-18 07:16:11 +02:00
Issue #1189 : Statistic page redesign
* Statistic page totally redesign, replace by a single graphic which display for last hours, days, months and years * Add Chart.js plugin for graphic representation * Add Moment.js plugin for time operations
This commit is contained in:
+102
-221
@@ -6,9 +6,9 @@
|
||||
// | file that was distributed with this source code. |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
if (!defined("PHPWG_ROOT_PATH"))
|
||||
if (!defined('PHPWG_ROOT_PATH'))
|
||||
{
|
||||
die ("Hacking attempt!");
|
||||
die ('Hacking attempt!');
|
||||
}
|
||||
|
||||
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
|
||||
@@ -18,7 +18,7 @@ include_once(PHPWG_ROOT_PATH.'admin/include/functions_history.inc.php');
|
||||
// | Functions |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
function get_summary($year = null, $month = null, $day = null)
|
||||
function get_last($last_number=60, $type='year')
|
||||
{
|
||||
$query = '
|
||||
SELECT
|
||||
@@ -29,42 +29,45 @@ SELECT
|
||||
nb_pages
|
||||
FROM '.HISTORY_SUMMARY_TABLE;
|
||||
|
||||
if (isset($day))
|
||||
if ($type === 'hour')
|
||||
{
|
||||
$query.= '
|
||||
WHERE year = '.$year.'
|
||||
AND month = '.$month.'
|
||||
AND day = '.$day.'
|
||||
WHERE year IS NOT NULL
|
||||
AND month IS NOT NULL
|
||||
AND day IS NOT NULL
|
||||
AND hour IS NOT NULL
|
||||
ORDER BY
|
||||
year ASC,
|
||||
month ASC,
|
||||
day ASC,
|
||||
hour ASC
|
||||
year DESC,
|
||||
month DESC,
|
||||
day DESC,
|
||||
hour DESC
|
||||
LIMIT '.$last_number.'
|
||||
;';
|
||||
}
|
||||
elseif (isset($month))
|
||||
elseif ($type === 'day')
|
||||
{
|
||||
$query.= '
|
||||
WHERE year = '.$year.'
|
||||
AND month = '.$month.'
|
||||
WHERE year IS NOT NULL
|
||||
AND month IS NOT NULL
|
||||
AND day IS NOT NULL
|
||||
AND hour IS NULL
|
||||
ORDER BY
|
||||
year ASC,
|
||||
month ASC,
|
||||
day ASC
|
||||
year DESC,
|
||||
month DESC,
|
||||
day DESC
|
||||
LIMIT '.$last_number.'
|
||||
;';
|
||||
}
|
||||
elseif (isset($year))
|
||||
elseif ($type === 'month')
|
||||
{
|
||||
$query.= '
|
||||
WHERE year = '.$year.'
|
||||
WHERE year IS NOT NULL
|
||||
AND month IS NOT NULL
|
||||
AND day IS NULL
|
||||
ORDER BY
|
||||
year ASC,
|
||||
month ASC
|
||||
year DESC,
|
||||
month DESC
|
||||
LIMIT '.$last_number.'
|
||||
;';
|
||||
}
|
||||
else
|
||||
@@ -73,7 +76,8 @@ SELECT
|
||||
WHERE year IS NOT NULL
|
||||
AND month IS NULL
|
||||
ORDER BY
|
||||
year ASC
|
||||
year DESC
|
||||
LIMIT '.$last_number.'
|
||||
;';
|
||||
}
|
||||
|
||||
@@ -94,94 +98,10 @@ SELECT
|
||||
|
||||
check_status(ACCESS_ADMINISTRATOR);
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Refresh summary from details |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
history_summarize();
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Page parameters check |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
foreach (array('day', 'month', 'year') as $key)
|
||||
{
|
||||
if (isset($_GET[$key]))
|
||||
{
|
||||
$page[$key] = (int)$_GET[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($page['day']))
|
||||
{
|
||||
if (!isset($page['month']))
|
||||
{
|
||||
die('month is missing in URL');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($page['month']))
|
||||
{
|
||||
if (!isset($page['year']))
|
||||
{
|
||||
die('year is missing in URL');
|
||||
}
|
||||
}
|
||||
|
||||
$summary_lines = get_summary(
|
||||
@$page['year'],
|
||||
@$page['month'],
|
||||
@$page['day']
|
||||
);
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Display statistics header |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
// page title creation
|
||||
$title_parts = array();
|
||||
|
||||
$url = PHPWG_ROOT_PATH.'admin.php?page=stats';
|
||||
|
||||
$title_parts[] = '<a href="'.$url.'">'.l10n('Overall').'</a>';
|
||||
|
||||
$period_label = l10n('Year');
|
||||
|
||||
if (isset($page['year']))
|
||||
{
|
||||
$url.= '&year='.$page['year'];
|
||||
|
||||
$title_parts[] = '<a href="'.$url.'">'.$page['year'].'</a>';
|
||||
|
||||
$period_label = l10n('Month');
|
||||
}
|
||||
|
||||
if (isset($page['month']))
|
||||
{
|
||||
$url.= '&month='.$page['month'];
|
||||
|
||||
$title_parts[] = '<a href="'.$url.'">'.$lang['month'][$page['month']].'</a>';
|
||||
|
||||
$period_label = l10n('Day');
|
||||
}
|
||||
|
||||
if (isset($page['day']))
|
||||
{
|
||||
$url.= '&day='.$page['day'];
|
||||
|
||||
$time = mktime(12, 0, 0, $page['month'], $page['day'], $page['year']);
|
||||
|
||||
$day_title = sprintf(
|
||||
'%u (%s)',
|
||||
$page['day'],
|
||||
$lang['day'][date('w', $time)]
|
||||
);
|
||||
|
||||
$title_parts[] = '<a href="'.$url.'">'.$day_title.'</a>';
|
||||
|
||||
$period_label = l10n('Hour');
|
||||
}
|
||||
|
||||
$template->set_filename('stats', 'stats.tpl');
|
||||
|
||||
// TabSheet initialization
|
||||
@@ -191,131 +111,92 @@ $base_url = get_root_url().'admin.php?page=history';
|
||||
|
||||
$template->assign(
|
||||
array(
|
||||
'L_STAT_TITLE' => implode($conf['level_separator'], $title_parts),
|
||||
'PERIOD_LABEL' => $period_label,
|
||||
'U_HELP' => get_root_url().'admin/popuphelp.php?page=history',
|
||||
'F_ACTION' => $base_url,
|
||||
)
|
||||
);
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Set missing unit to 0 |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
function set_missing_value($unit, $data)
|
||||
{
|
||||
$limit = count($data);
|
||||
$result = array();
|
||||
$date = get_date_object($data[count($data) - 1]);
|
||||
|
||||
if ($unit == 'year')
|
||||
{
|
||||
$date_format = 'Y';
|
||||
$date_add = 'P1Y';
|
||||
}
|
||||
else if ($unit == 'month')
|
||||
{
|
||||
$date_format = 'Y-m';
|
||||
$date_add = 'P1M';
|
||||
}
|
||||
else if ($unit == 'day')
|
||||
{
|
||||
$date_format = 'Y-m-d';
|
||||
$date_add = 'P1D';
|
||||
}
|
||||
else if ($unit == 'hour')
|
||||
{
|
||||
$date_format = 'Y-m-d\TH:00';
|
||||
$date_add = 'PT1H';
|
||||
}
|
||||
|
||||
for ($i=0; $i < $limit; $i++)
|
||||
{
|
||||
$result[$date->format($date_format)] = 0;
|
||||
$date->add(new DateInterval($date_add));
|
||||
}
|
||||
|
||||
foreach ($data as $value)
|
||||
{
|
||||
$str = get_date_object($value)->format($date_format);
|
||||
if (isset($result[$str]))
|
||||
{
|
||||
$result[$str] += $value['nb_pages'];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function get_date_object($row) {
|
||||
$date_string = $row['year'];
|
||||
if ($row['month'] != null)
|
||||
{
|
||||
$date_string = $date_string.'-'.$row['month'] ;
|
||||
if ($row['day'] != null)
|
||||
{
|
||||
$date_string = $date_string.'-'.$row['day'];
|
||||
if ($row['hour'] != null)
|
||||
{
|
||||
$date_string = $date_string.' '.$row['hour'].':00';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$date_string .= '-1';
|
||||
}
|
||||
|
||||
return new DateTime($date_string);
|
||||
}
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Display statistic rows |
|
||||
// +-----------------------------------------------------------------------+
|
||||
|
||||
$max_width = 400;
|
||||
$template->append('lastHours', set_missing_value('hour',get_last(72, 'hour')));
|
||||
$template->append('lastDays', set_missing_value('day',get_last(90, 'day')));
|
||||
$template->append('lastMonths', set_missing_value('month',get_last(24, 'month')));
|
||||
$template->append('lastYears', set_missing_value('year',get_last(60, 'year')));
|
||||
|
||||
$datas = array();
|
||||
|
||||
if (isset($page['day']))
|
||||
{
|
||||
$key = 'hour';
|
||||
$min_x = 0;
|
||||
$max_x = 23;
|
||||
}
|
||||
elseif (isset($page['month']))
|
||||
{
|
||||
$key = 'day';
|
||||
$min_x = 1;
|
||||
$max_x = date(
|
||||
't',
|
||||
mktime(12, 0, 0, $page['month'], 1, $page['year'])
|
||||
);
|
||||
}
|
||||
elseif (isset($page['year']))
|
||||
{
|
||||
$key = 'month';
|
||||
$min_x = 1;
|
||||
$max_x = 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = 'year';
|
||||
}
|
||||
|
||||
$max_pages = 1;
|
||||
foreach ($summary_lines as $line)
|
||||
{
|
||||
if ($line['nb_pages'] > $max_pages)
|
||||
{
|
||||
$max_pages = $line['nb_pages'];
|
||||
}
|
||||
|
||||
$datas[ $line[$key] ] = $line['nb_pages'];
|
||||
}
|
||||
|
||||
if (!isset($min_x) and !isset($max_x) and count($datas) > 0)
|
||||
{
|
||||
$min_x = min(array_keys($datas));
|
||||
$max_x = max(array_keys($datas));
|
||||
}
|
||||
|
||||
if (count($datas) > 0)
|
||||
{
|
||||
for ($i = $min_x; $i <= $max_x; $i++)
|
||||
{
|
||||
if (!isset($datas[$i]))
|
||||
{
|
||||
$datas[$i] = 0;
|
||||
}
|
||||
|
||||
$url = null;
|
||||
|
||||
if (isset($page['day']))
|
||||
{
|
||||
$value = sprintf('%02u', $i);
|
||||
}
|
||||
else if (isset($page['month']))
|
||||
{
|
||||
$url =
|
||||
get_root_url().'admin.php'
|
||||
.'?page=stats'
|
||||
.'&year='.$page['year']
|
||||
.'&month='.$page['month']
|
||||
.'&day='.$i
|
||||
;
|
||||
|
||||
$time = mktime(12, 0, 0, $page['month'], $i, $page['year']);
|
||||
|
||||
$value = $i.' ('.$lang['day'][date('w', $time)].')';
|
||||
}
|
||||
else if (isset($page['year']))
|
||||
{
|
||||
$url =
|
||||
get_root_url().'admin.php'
|
||||
.'?page=stats'
|
||||
.'&year='.$page['year']
|
||||
.'&month='.$i
|
||||
;
|
||||
|
||||
$value = $lang['month'][$i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// at least the year is defined
|
||||
$url =
|
||||
get_root_url().'admin.php'
|
||||
.'?page=stats'
|
||||
.'&year='.$i
|
||||
;
|
||||
|
||||
$value = $i;
|
||||
}
|
||||
|
||||
if ($datas[$i] != 0 and isset($url))
|
||||
{
|
||||
$value = '<a href="'.$url.'">'.$value.'</a>';
|
||||
}
|
||||
|
||||
$template->append(
|
||||
'statrows',
|
||||
array(
|
||||
'VALUE' => $value,
|
||||
'PAGES' => $datas[$i],
|
||||
'WIDTH' => ceil(($datas[$i] * $max_width) / $max_pages ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Sending html code |
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*-------
|
||||
Data Get
|
||||
-------*/
|
||||
data = {};
|
||||
data["hours"] = $("#data").data("hours")[0];
|
||||
data["days"] = $("#data").data("days")[0];
|
||||
data["months"] = $("#data").data("months")[0];
|
||||
data["years"] = $("#data").data("years")[0];
|
||||
|
||||
data_unit = {
|
||||
"hours":"day",
|
||||
"days":"month",
|
||||
"months": "year",
|
||||
"years": "year"
|
||||
}
|
||||
|
||||
/*-------
|
||||
Creating graph
|
||||
-------*/
|
||||
var ctx = document.getElementById('stat-graph').getContext('2d');
|
||||
|
||||
var gradient = ctx.createLinearGradient(0,400, 0,0);
|
||||
gradient.addColorStop(0, 'rgba(255,166,70,0)');
|
||||
gradient.addColorStop(1, '#FFA646');
|
||||
|
||||
Chart.defaults.global.elements.point.radius = 0.1;
|
||||
Chart.defaults.global.elements.point.hitRadius = 10
|
||||
var statGraph = new Chart(ctx, {
|
||||
type: 'line',
|
||||
maintainAspectRatio: false,
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
tooltipFormat: 'll'
|
||||
},
|
||||
gridLines: {
|
||||
display: false
|
||||
}
|
||||
}],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var displayOptions = {
|
||||
backgroundColor: gradient,
|
||||
borderColor: '#FFA646',
|
||||
lineTension : 0.2
|
||||
}
|
||||
|
||||
function changeData(dataType, label, options = displayOptions) {
|
||||
statGraph.data = {
|
||||
datasets: [{
|
||||
label: label,
|
||||
data: getValues(data[dataType]),
|
||||
...options
|
||||
}]
|
||||
}
|
||||
statGraph.options.scales.xAxes.forEach(axe => {
|
||||
axe.time.tooltipFormat = str_tooltip_format[dataType];
|
||||
axe.time.unit = data_unit[dataType];
|
||||
axe.time.displayFormats = str_unit_format;
|
||||
})
|
||||
statGraph.update();
|
||||
}
|
||||
|
||||
function getValues(data) {
|
||||
values = [];
|
||||
Object.keys(data).forEach(function(key) {
|
||||
var newPoint = {
|
||||
x:new Date(key),
|
||||
y:data[key]
|
||||
}
|
||||
values.push(newPoint)
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
function addAZero(number) {
|
||||
if (number < 10)
|
||||
return "0"+number;
|
||||
return number;
|
||||
}
|
||||
|
||||
$(".stat-data-selector label").on("click", function(){
|
||||
let dataType = $(this).data("value");
|
||||
changeData(dataType, str_number_page_visited)
|
||||
})
|
||||
|
||||
/*-------
|
||||
Initialize the page
|
||||
-------*/
|
||||
$(function() {
|
||||
let dataType = $(".stat-data-selector input:checked + label").data("value");
|
||||
changeData(dataType, str_number_page_visited)
|
||||
})
|
||||
@@ -1,25 +1,45 @@
|
||||
{footer_script}
|
||||
var str_months_names = ["{'January'|@translate}","{'February'|@translate}","{'March'|@translate}","{'April'|@translate}","{'May'|@translate}","{'June'|@translate}","{'July'|@translate}","{'August'|@translate}","{'September'|@translate}","{'October'|@translate}","{'November'|@translate}","{'December'|@translate}"];
|
||||
var str_number_page_visited = "{'Number of visited pages'|@translate}";
|
||||
var str_tooltip_format = {
|
||||
"years":"YYYY",
|
||||
"months":"MMMM YYYY",
|
||||
"days":"DD MMM",
|
||||
"hours":"H[h] - dddd"
|
||||
};
|
||||
var str_unit_format = {
|
||||
"day":"dddd",
|
||||
"month":"MMM YYYY"
|
||||
}
|
||||
moment.locale({'en'|@translate});
|
||||
{/footer_script}
|
||||
|
||||
{combine_script id='chart.js' load='footer' path='themes/default/js/plugins/Chart.min.js'}
|
||||
{combine_css path="themes/default/js/plugins/Chart.min.css"}
|
||||
|
||||
{combine_script id='moment-with-locales.js' path='themes/default/js/plugins/moment-with-locales.min.js'}
|
||||
|
||||
{combine_script id='stats' load='footer' path='admin/themes/default/js/stats.js'}
|
||||
|
||||
<div class="titrePage">
|
||||
<h2>{'History'|@translate} {$TABSHEET_TITLE}</h2>
|
||||
<h2>{'History'|@translate}</h2>
|
||||
</div>
|
||||
|
||||
<h3>{$L_STAT_TITLE}</h3>
|
||||
<div id="data" data-hours='{json_encode($lastHours)}' data-days='{json_encode($lastDays)}' data-months='{json_encode($lastMonths)}' data-years='{json_encode($lastYears)}'></div>
|
||||
|
||||
<table class="table2" id="dailyStats">
|
||||
<tr class="throw">
|
||||
<th>{$PERIOD_LABEL}</th>
|
||||
<th>{'Pages seen'|@translate}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<div class="stat-legend-container">
|
||||
<div class="stat-data-selector">
|
||||
<input type="radio" id="hours-selector" name="stat-data-type" checked>
|
||||
<label for="hours-selector" data-value="hours">{"Hours"|@translate}</label>
|
||||
<input type="radio" id="days-selector" name="stat-data-type">
|
||||
<label for="days-selector" data-value="days">{"Day"|@translate}</label>
|
||||
<input type="radio" id="months-selector" name="stat-data-type">
|
||||
<label for="months-selector" data-value="months">{"Month"|@translate}</label>
|
||||
<input type="radio" id="years-selector" name="stat-data-type">
|
||||
<label for="years-selector" data-value="years">{"Year"|@translate}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if not empty($statrows)}
|
||||
{foreach from=$statrows item=row}
|
||||
<tr>
|
||||
<td style="white-space: nowrap">{$row.VALUE}</td>
|
||||
<td class="number">{$row.PAGES}</td>
|
||||
<td><div class="statBar" style="width:{$row.WIDTH}px"></div></td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
{/if}
|
||||
|
||||
</table>
|
||||
<div class="stat-graph-container">
|
||||
<canvas id="stat-graph" width="400" height="200" role="img"><p>Your browser does not support the canvas element.</p></canvas>
|
||||
</div>
|
||||
|
||||
@@ -248,10 +248,43 @@ TABLE.doubleSelect SELECT.categoryList {
|
||||
width: 100%; max-width: 100%; overflow-x: auto;
|
||||
}
|
||||
|
||||
.statBar {
|
||||
height: 10px;
|
||||
background-color: #ff7700;
|
||||
border: 1px solid #666;
|
||||
.stat-legend-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.stat-data-selector {
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stat-data-selector label {
|
||||
color: black;
|
||||
padding: 10px;
|
||||
background-color: #eee;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.stat-data-selector label:hover {
|
||||
background-color: #ccc
|
||||
}
|
||||
|
||||
.stat-data-selector input:checked + label {
|
||||
background-color: #FFA646;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stat-data-selector input{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stat-graph-container {
|
||||
margin: auto;
|
||||
position: relative;
|
||||
width: 80%;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.over{
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
|
||||
+7
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user