diff options
| author | 2021-10-16 12:00:07 +0200 | |
|---|---|---|
| committer | 2021-10-16 12:00:07 +0200 | |
| commit | 02641de32ecc6e0e4fd9de030399728080b6ed41 (patch) | |
| tree | c01ce17b89c8225f51a796e0bef589498e56a14f /app | |
| parent | ebf9c70ebd4356d98fa7c2513aaab48fa14c7c9b (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.php | 82 | ||||
| -rw-r--r-- | app/Models/StatsDAO.php | 30 | ||||
| -rw-r--r-- | app/Models/StatsDAOPGSQL.php | 15 | ||||
| -rw-r--r-- | app/Models/StatsDAOSQLite.php | 16 | ||||
| -rw-r--r-- | app/views/stats/index.phtml | 54 | ||||
| -rw-r--r-- | app/views/stats/repartition.phtml | 53 |
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> |
