aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGravatar maTh <math-home@web.de> 2021-10-16 12:00:07 +0200
committerGravatar GitHub <noreply@github.com> 2021-10-16 12:00:07 +0200
commit02641de32ecc6e0e4fd9de030399728080b6ed41 (patch)
treec01ce17b89c8225f51a796e0bef589498e56a14f /app
parentebf9c70ebd4356d98fa7c2513aaab48fa14c7c9b (diff)
Stats: replace flotr2 with chart.js (#3858)
* include Chart.js * page: main statistics. Flotr.js replaced with Chart.js * main stats + repartition * Delete: repartition.js + stats.js * delete flotr2 * add libs in README * polish * code polish * fixed amount of week days and months * added manget link for LibreJS * added: @license-end * phpcbf + jshint formatting * delete old code * fix stats * fix Comments * finally I found the issue and fixed its best * fix the month stats * Whitespace fixes * Remove flotr2 * Rename to chart.min.js * Remove console.log Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Diffstat (limited to 'app')
-rw-r--r--app/Controllers/statsController.php82
-rw-r--r--app/Models/StatsDAO.php30
-rw-r--r--app/Models/StatsDAOPGSQL.php15
-rw-r--r--app/Models/StatsDAOSQLite.php16
-rw-r--r--app/views/stats/index.phtml54
-rw-r--r--app/views/stats/repartition.phtml53
6 files changed, 192 insertions, 58 deletions
diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php
index 3eeb0a8f7..c9a8cdc0c 100644
--- a/app/Controllers/statsController.php
+++ b/app/Controllers/statsController.php
@@ -49,22 +49,43 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
*
* It displays the statistic main page.
* The values computed to display the page are:
- * - repartition of read/unread/favorite/not favorite
- * - number of article per day
- * - number of feed by category
- * - number of article by category
- * - list of most prolific feed
+ * - repartition of read/unread/favorite/not favorite (repartition)
+ * - number of article per day (entryCount)
+ * - number of feed by category (feedByCategory)
+ * - number of article by category (entryByCategory)
+ * - list of most prolific feed (topFeed)
*/
public function indexAction() {
$statsDAO = FreshRSS_Factory::createStatsDAO();
- Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js')));
+ Minz_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
+
$this->view->repartition = $statsDAO->calculateEntryRepartition();
+
$entryCount = $statsDAO->calculateEntryCount();
- $this->view->count = $this->convertToSerie($entryCount);
+ $this->view->entryCount = $entryCount;
$this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2);
- $this->view->feedByCategory = $this->convertToPieSerie($statsDAO->calculateFeedByCategory());
- $this->view->entryByCategory = $this->convertToPieSerie($statsDAO->calculateEntryByCategory());
+
+ $feedByCategory_calculated = $statsDAO->calculateFeedByCategory();
+ for ($i = 0; $i < count($feedByCategory_calculated); $i++) {
+ $feedByCategory['label'][$i] = $feedByCategory_calculated[$i]['label'];
+ $feedByCategory['data'][$i] = $feedByCategory_calculated[$i]['data'];
+ }
+ $this->view->feedByCategory = $feedByCategory;
+
+ $entryByCategory_calculated = $statsDAO->calculateEntryByCategory();
+ for ($i = 0; $i < count($entryByCategory_calculated); $i++) {
+ $entryByCategory['label'][$i] = $entryByCategory_calculated[$i]['label'];
+ $entryByCategory['data'][$i] = $entryByCategory_calculated[$i]['data'];
+ }
+ $this->view->entryByCategory = $entryByCategory;
+
$this->view->topFeed = $statsDAO->calculateTopFeed();
+
+ for ($i = 0; $i < 30; $i++) {
+ $last30DaysLabels[$i] = date('d.m.Y', strtotime((-30 + $i) . ' days'));
+ }
+
+ $this->view->last30DaysLabels = $last30DaysLabels;
}
/**
@@ -153,21 +174,34 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
* for the average.
*/
public function repartitionAction() {
- $statsDAO = FreshRSS_Factory::createStatsDAO();
- $categoryDAO = FreshRSS_Factory::createCategoryDao();
- $feedDAO = FreshRSS_Factory::createFeedDao();
- Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js')));
+ $statsDAO = FreshRSS_Factory::createStatsDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
+ $feedDAO = FreshRSS_Factory::createFeedDao();
+
+ Minz_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
+
$id = Minz_Request::param('id', null);
- $this->view->categories = $categoryDAO->listCategories();
- $this->view->feed = $feedDAO->searchById($id);
- $this->view->days = $statsDAO->getDays();
- $this->view->months = $statsDAO->getMonths();
- $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id);
- $this->view->repartitionHour = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerHour($id));
- $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id);
- $this->view->repartitionDayOfWeek = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id));
- $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id);
- $this->view->repartitionMonth = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerMonth($id));
- $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id);
+
+ $this->view->categories = $categoryDAO->listCategories();
+ $this->view->feed = $feedDAO->searchById($id);
+ $this->view->days = $statsDAO->getDays();
+ $this->view->months = $statsDAO->getMonths();
+
+ $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id);
+
+ $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
+ $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id);
+
+ $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
+ $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id);
+
+ $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
+ $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id);
+
+ for ($i = 0; $i < 24; $i++) {
+ $hours24Labels[$i] = $i . ':xx';
+ }
+
+ $this->view->hours24Labels = $hours24Labels;
}
}
diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php
index 824535c2d..33e5426b5 100644
--- a/app/Models/StatsDAO.php
+++ b/app/Models/StatsDAO.php
@@ -98,7 +98,7 @@ SQL;
* Calculates the number of article per hour of the day per feed
*
* @param integer $feed id
- * @return string
+ * @return array
*/
public function calculateEntryRepartitionPerFeedPerHour($feed = null) {
return $this->calculateEntryRepartitionPerFeedPerPeriod('%H', $feed);
@@ -108,7 +108,7 @@ SQL;
* Calculates the number of article per day of week per feed
*
* @param integer $feed id
- * @return string
+ * @return array
*/
public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) {
return $this->calculateEntryRepartitionPerFeedPerPeriod('%w', $feed);
@@ -118,18 +118,22 @@ SQL;
* Calculates the number of article per month per feed
*
* @param integer $feed
- * @return string
+ * @return array
*/
public function calculateEntryRepartitionPerFeedPerMonth($feed = null) {
- return $this->calculateEntryRepartitionPerFeedPerPeriod('%m', $feed);
+ $monthRepartition = $this->calculateEntryRepartitionPerFeedPerPeriod('%m', $feed);
+ // cut out the 0th month (Jan=1, Dec=12)
+ \array_splice($monthRepartition, 0, 1);
+ return $monthRepartition;
}
+
/**
* Calculates the number of article per period per feed
*
* @param string $period format string to use for grouping
* @param integer $feed id
- * @return string
+ * @return array
*/
protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) {
$restrict = '';
@@ -148,7 +152,21 @@ SQL;
$stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
- $repartition = array();
+ switch ($period) {
+ case '%H':
+ $periodMax = 24;
+ break;
+ case '%w':
+ $periodMax = 7;
+ break;
+ case '%m':
+ $periodMax = 12;
+ break;
+ default:
+ $periodMax = 30;
+ }
+
+ $repartition = array_fill(0, $periodMax, 0);
foreach ($res as $value) {
$repartition[(int) $value['period']] = (int) $value['count'];
}
diff --git a/app/Models/StatsDAOPGSQL.php b/app/Models/StatsDAOPGSQL.php
index 4a66068cb..f36d29770 100644
--- a/app/Models/StatsDAOPGSQL.php
+++ b/app/Models/StatsDAOPGSQL.php
@@ -56,6 +56,21 @@ SQL;
$stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
+ switch ($period) {
+ case 'hour':
+ $periodMax = 24;
+ break;
+ case 'day':
+ $periodMax = 7;
+ break;
+ case 'month':
+ $periodMax = 12;
+ break;
+ default:
+ $periodMax = 30;
+ }
+
+ $repartition = array_fill(0, $periodMax, 0);
foreach ($res as $value) {
$repartition[(int) $value['period']] = (int) $value['count'];
}
diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php
index f96f8f479..d262b40f8 100644
--- a/app/Models/StatsDAOSQLite.php
+++ b/app/Models/StatsDAOSQLite.php
@@ -24,7 +24,21 @@ SQL;
$stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
- $repartition = array();
+ switch ($period) {
+ case '%H':
+ $periodMax = 24;
+ break;
+ case '%w':
+ $periodMax = 7;
+ break;
+ case '%m':
+ $periodMax = 12;
+ break;
+ default:
+ $periodMax = 30;
+ }
+
+ $repartition = array_fill(0, $periodMax, 0);
foreach ($res as $value) {
$repartition[(int) $value['period']] = (int) $value['count'];
}
diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml
index db1ccd601..dff20041d 100644
--- a/app/views/stats/index.phtml
+++ b/app/views/stats/index.phtml
@@ -69,29 +69,55 @@
<div class="stat">
<h2><?= _t('admin.stats.entry_per_day') ?></h2>
- <div id="statsEntryPerDay" class="statGraph"></div>
+ <div>
+ <canvas id="statsEntriesPerDay"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsEntriesPerDay',
+ 'charttype' => 'barWithAverage',
+ 'labelBarChart' => _t('admin.stats.entry_count'),
+ 'dataBarChart' => $this->entryCount,
+ 'labelAverage' => 'Average ('.$this->average.')',
+ 'dataAverage' => $this->average,
+ 'xAxisLabels' => $this->last30DaysLabels,
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
<div class="stat half">
<h2><?= _t('admin.stats.feed_per_category') ?></h2>
- <div id="statsFeedPerCategory" class="statGraph"></div>
- <div id="statsFeedPerCategoryLegend"></div>
+ <div>
+ <canvas id="statsFeedsPerCategory"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsFeedsPerCategory',
+ 'charttype' => 'doughnut',
+ 'data' => $this->feedByCategory['data'],
+ 'labels' => $this->feedByCategory['label'],
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
<div class="stat half">
<h2><?= _t('admin.stats.entry_per_category') ?></h2>
- <div id="statsEntryPerCategory" class="statGraph"></div>
- <div id="statsEntryPerCategoryLegend"></div>
+ <div>
+ <canvas id="statsEntriesPerCategory"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsEntriesPerCategory',
+ 'charttype' => 'doughnut',
+ 'data' => $this->entryByCategory['data'],
+ 'labels' => $this->entryByCategory['label'],
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
</div>
</div>
-<script id="jsonStats" type="application/json"><?php
-echo json_encode(array(
- 'average' => $this->average,
- 'dataCount' => $this->count,
- 'feedByCategory' => $this->feedByCategory,
- 'entryByCategory' => $this->entryByCategory,
-), JSON_UNESCAPED_UNICODE);
-?></script>
-<script src="../scripts/stats.js?<?= @filemtime(PUBLIC_PATH . '/scripts/stats.js') ?>"></script>
+<script src="../scripts/statsWithChartjs.js?<?= @filemtime(PUBLIC_PATH . '/scripts/statsWithChartjs.js') ?>"></script>
diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml
index 88086213e..2cf65b3fb 100644
--- a/app/views/stats/repartition.phtml
+++ b/app/views/stats/repartition.phtml
@@ -53,28 +53,55 @@
<div class="stat">
<h2><?= _t('admin.stats.entry_per_hour', $this->averageHour) ?></h2>
- <div id="statsEntryPerHour" class="statGraph"></div>
+ <div>
+ <canvas id="statsEntriesPerHour"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsEntriesPerHour',
+ 'charttype' => 'bar',
+ 'data' => $this->repartitionHour,
+ 'label' => _t('admin.stats.entry_count'),
+ 'xAxisLabels' => $this->hours24Labels
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
<div class="stat half">
<h2><?= _t('admin.stats.entry_per_day_of_week', $this->averageDayOfWeek) ?></h2>
- <div id="statsEntryPerDayOfWeek" class="statGraph"></div>
+ <div>
+ <canvas id="statsEntriesPerDayOfWeek"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsEntriesPerDayOfWeek',
+ 'charttype' => 'bar',
+ 'data' => $this->repartitionDayOfWeek,
+ 'label' => _t('admin.stats.entry_count'),
+ 'xAxisLabels' => $this->days,
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
<div class="stat half">
<h2><?= _t('admin.stats.entry_per_month', $this->averageMonth) ?></h2>
- <div id="statsEntryPerMonth" class="statGraph"></div>
+ <div>
+ <canvas id="statsEntriesPerMonth"></canvas>
+ <script class="jsonData-stats" type="application/json">
+ <?php
+ echo json_encode(array(
+ 'canvasID' => 'statsEntriesPerMonth',
+ 'charttype' => 'bar',
+ 'data' => $this->repartitionMonth,
+ 'label' => _t('admin.stats.entry_count'),
+ 'xAxisLabels' => $this->months,
+ ), JSON_UNESCAPED_UNICODE);
+ ?></script>
+ </div>
</div>
</div>
</div>
-<script id="jsonRepartition" type="application/json"><?php
-echo htmlspecialchars(json_encode(array(
- 'repartitionHour' => $this->repartitionHour,
- 'repartitionDayOfWeek' => $this->repartitionDayOfWeek,
- 'days' => $this->days,
- 'repartitionMonth' => $this->repartitionMonth,
- 'months' => $this->months,
-), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES, 'UTF-8');
-?></script>
-<script src="../scripts/repartition.js?<?= @filemtime(PUBLIC_PATH . '/scripts/repartition.js') ?>"></script>
+<script src="../scripts/statsWithChartjs.js?<?= @filemtime(PUBLIC_PATH . '/scripts/statsWithChartjs.js') ?>"></script>