| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- <?php
- declare(strict_types=1);
- /** @var FreshRSS_ViewStats $this */
- $this->partial('aside_subscription');
- ?>
- <main class="post">
- <h1><?= _t('admin.stats.main') ?></h1>
- <div class="box">
- <div class="box-title"><h2><?= _t('admin.stats.entry_repartition') ?></h2></div>
- <div class="box-content scrollbar-thin">
- <table>
- <thead>
- <tr>
- <th> </th>
- <th><?= _t('admin.stats.main_stream') ?></th>
- <th><?= _t('admin.stats.all_feeds') ?></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th><?= _t('admin.stats.status_total') ?></th>
- <td class="numeric"><?= format_number($this->repartitions['main_stream']['total'] ?? -1) ?></td>
- <td class="numeric"><?= format_number($this->repartitions['all_feeds']['total'] ?? -1) ?></td>
- </tr>
- <tr>
- <th><?= _t('admin.stats.status_read') ?></th>
- <td class="numeric"><?= format_number($this->repartitions['main_stream']['count_reads'] ?? -1) ?></td>
- <td class="numeric"><?= format_number($this->repartitions['all_feeds']['count_reads'] ?? -1) ?></td>
- </tr>
- <tr>
- <th><?= _t('admin.stats.status_unread') ?></th>
- <td class="numeric"><?= format_number($this->repartitions['main_stream']['count_unreads'] ?? -1) ?></td>
- <td class="numeric"><?= format_number($this->repartitions['all_feeds']['count_unreads'] ?? -1) ?></td>
- </tr>
- <tr>
- <th><?= _t('admin.stats.status_favorites') ?></th>
- <td class="numeric"><?= format_number($this->repartitions['main_stream']['count_favorites'] ?? -1) ?></td>
- <td class="numeric"><?= format_number($this->repartitions['all_feeds']['count_favorites'] ?? -1) ?></td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <div class="box double-height">
- <div class="box-title"><h2><?= _t('admin.stats.top_feed') ?></h2></div>
- <div class="box-content scrollbar-thin">
- <table>
- <thead>
- <tr>
- <th><?= _t('admin.stats.feed') ?></th>
- <th><?= _t('admin.stats.category') ?></th>
- <th><?= _t('admin.stats.entry_count') ?></th>
- <th><?= _t('admin.stats.percent_of_total') ?></th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($this->topFeed as $feed): ?>
- <tr>
- <td><a href="<?= _url('stats', 'repartition', 'id', $feed['id']) ?>"><?= $feed['name'] ?></a></td>
- <td><?= $feed['category'] ?></td>
- <td class="numeric"><?= format_number($feed['count']) ?></td>
- <td class="numeric"><?php
- if (!empty($this->repartitions['all_feeds']['total'])) {
- echo format_number($feed['count'] / $this->repartitions['all_feeds']['total'] * 100, 1);
- }
- ?></td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- </div>
- </div>
- <br />
- <div class="box double-width double-height">
- <div class="box-title"><h2><?= _t('admin.stats.entry_per_day') ?></h2></div>
- <div class="box-content scrollbar-thin">
- <canvas id="statsEntriesPerDay"></canvas>
- <script class="jsonData-stats" type="application/json">
- <?= json_encode([
- '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>
- <?php
- // Function to generate a color palette
- /**
- * Generate a color palette.
- *
- * @param int $count The number of colors to generate.
- * @return array<int,string> An array of HSL color strings.
- */
- function generateColorPalette(int $count): array {
- $colors = [];
- for ($i = 0; $i < $count; $i++) {
- $hue = ($i / $count) * 360; // Distribute colors evenly around the color wheel
- $saturation = 70; // Fixed saturation
- $lightness = 50; // Fixed lightness
- $colors[] = "hsl($hue, {$saturation}%, {$lightness}%)";
- }
- return $colors;
- }
- // 1. Get all unique category labels and sort them
- $allLabels = array_unique(array_merge($this->feedByCategory['label'], $this->entryByCategory['label']));
- sort($allLabels); // Ensure consistent order
- // 2. Generate a color palette based on the number of unique categories
- $colorPalette = generateColorPalette(count($allLabels));
- // 3. Map categories to colors
- $colorMap = array_combine($allLabels, $colorPalette);
- // 4. Align data and labels for both charts
- $feedData = array_fill_keys($allLabels, 0); // Initialize data with all categories
- foreach ($this->feedByCategory['label'] as $index => $label) {
- $feedData[$label] = $this->feedByCategory['data'][$index];
- }
- $entryData = array_fill_keys($allLabels, 0); // Initialize data with all categories
- foreach ($this->entryByCategory['label'] as $index => $label) {
- $entryData[$label] = $this->entryByCategory['data'][$index];
- }
- // Final data and labels
- $feedLabels = array_keys($feedData);
- $feedColors = array_map(fn($label) => $colorMap[$label], $feedLabels);
- $feedValues = array_values($feedData);
- $entryLabels = array_keys($entryData);
- $entryColors = array_map(fn($label) => $colorMap[$label], $entryLabels);
- $entryValues = array_values($entryData);
- ?>
- <br id="stats_per_category" />
- <div class="box double-height" id="feed_per_category">
- <div class="box-title"><h2><?= _t('admin.stats.feed_per_category') ?></h2><a href="#feed_per_category" class="btn target-hidden">+</a><a href="#stats_per_category" class="btn target-visible">-</a></div>
- <div class="box-content scrollbar-thin">
- <canvas id="statsFeedsPerCategory"></canvas>
- <script class="jsonData-stats" type="application/json">
- <?= json_encode([
- 'canvasID' => 'statsFeedsPerCategory',
- 'charttype' => 'doughnut',
- 'data' => $feedValues,
- 'labels' => $feedLabels,
- 'backgroundColor' => $feedColors,
- ], JSON_UNESCAPED_UNICODE); ?>
- </script>
- </div>
- </div>
- <div class="box double-height" id="entry_per_category">
- <div class="box-title"><h2><?= _t('admin.stats.entry_per_category') ?></h2><a href="#entry_per_category" class="btn target-hidden">+</a><a href="#stats_per_category" class="btn target-visible">-</a></div>
- <div class="box-content scrollbar-thin">
- <canvas id="statsEntriesPerCategory"></canvas>
- <script class="jsonData-stats" type="application/json">
- <?= json_encode([
- 'canvasID' => 'statsEntriesPerCategory',
- 'charttype' => 'doughnut',
- 'data' => $entryValues,
- 'labels' => $entryLabels,
- 'backgroundColor' => $entryColors,
- ], JSON_UNESCAPED_UNICODE); ?>
- </script>
- </div>
- </div>
- </div>
- </main>
- <script src="../scripts/statsWithChartjs.js?<?= @filemtime(PUBLIC_PATH . '/scripts/statsWithChartjs.js') ?>"></script>
|