Fixing stats page, replacing ob/highcharts-bundle with own implementation based on ghunti/highcharts-php. Some refactoring.
This commit is contained in:
parent
3a69565ecb
commit
4c33ce9d84
|
@ -13,6 +13,7 @@
|
||||||
"doctrine/doctrine-fixtures-bundle": "^3.4",
|
"doctrine/doctrine-fixtures-bundle": "^3.4",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.2",
|
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||||
"doctrine/orm": "^2.14",
|
"doctrine/orm": "^2.14",
|
||||||
|
"ghunti/highcharts-php": "^5.0",
|
||||||
"jms/serializer-bundle": "^5.2",
|
"jms/serializer-bundle": "^5.2",
|
||||||
"knplabs/knp-paginator-bundle": "^6.2",
|
"knplabs/knp-paginator-bundle": "^6.2",
|
||||||
"league/commonmark": "^2.4",
|
"league/commonmark": "^2.4",
|
||||||
|
|
56
composer.lock
generated
56
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6088d0629768085da296aa5598445c4f",
|
"content-hash": "274812d219a3d19c925c0e67b5f86926",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "dflydev/dot-access-data",
|
"name": "dflydev/dot-access-data",
|
||||||
|
@ -1635,6 +1635,60 @@
|
||||||
},
|
},
|
||||||
"time": "2022-05-23T21:33:49+00:00"
|
"time": "2022-05-23T21:33:49+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ghunti/highcharts-php",
|
||||||
|
"version": "v5.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ghunti/HighchartsPHP.git",
|
||||||
|
"reference": "7bccba4278fcc5d3a50cf6aa35975b0943a03cad"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/ghunti/HighchartsPHP/zipball/7bccba4278fcc5d3a50cf6aa35975b0943a03cad",
|
||||||
|
"reference": "7bccba4278fcc5d3a50cf6aa35975b0943a03cad",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Ghunti\\HighchartsPHP\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Gonçalo Queirós",
|
||||||
|
"email": "mail@goncaloqueiros.net",
|
||||||
|
"homepage": "http://goncaloqueiros.net",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A php wrapper for highcharts and highstock javascript libraries",
|
||||||
|
"homepage": "https://goncaloqueiros.net/highcharts.php",
|
||||||
|
"keywords": [
|
||||||
|
"charts",
|
||||||
|
"highcharts",
|
||||||
|
"highstock",
|
||||||
|
"javascript",
|
||||||
|
"php"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"email": "mail@goncaloqueiros.net",
|
||||||
|
"issues": "https://github.com/ghunti/HighchartsPHP/issues",
|
||||||
|
"source": "https://github.com/ghunti/HighchartsPHP"
|
||||||
|
},
|
||||||
|
"time": "2023-04-26T21:37:31+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "jms/metadata",
|
"name": "jms/metadata",
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
|
|
|
@ -26,7 +26,7 @@ user_show:
|
||||||
|
|
||||||
statistics:
|
statistics:
|
||||||
path: /statistics
|
path: /statistics
|
||||||
defaults: { _controller: App\Controller\UserController::top }
|
defaults: { _controller: App\Controller\StatsController::show }
|
||||||
methods: [GET]
|
methods: [GET]
|
||||||
|
|
||||||
events_last:
|
events_last:
|
||||||
|
|
|
@ -89,7 +89,7 @@ class UserRepositoryTest extends KernelTestCase
|
||||||
|
|
||||||
public function testGetTopUsers()
|
public function testGetTopUsers()
|
||||||
{
|
{
|
||||||
$topUsers = $this->userRepo->getTopUsers();
|
$topUsers = $this->userRepo->getTopUsersBySubscribersCount();
|
||||||
|
|
||||||
$this->assertCount(3, $topUsers, 'Found not exactly 3 top users');
|
$this->assertCount(3, $topUsers, 'Found not exactly 3 top users');
|
||||||
|
|
||||||
|
|
78
src/Chart/ChartGenerator.php
Normal file
78
src/Chart/ChartGenerator.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Chart;
|
||||||
|
|
||||||
|
use App\DTO\DailyEventsDTO;
|
||||||
|
use App\DTO\TopUserDTO;
|
||||||
|
use Ghunti\HighchartsPHP\Highchart;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class ChartGenerator
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DailyEventsDTO[] $events
|
||||||
|
*/
|
||||||
|
public function eventsDynamicChart(array $events): Highchart
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$data[$event->date->format('d.m')] = $event->eventsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createChart('line', $data, 'Events by day', 'amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TopUserDTO[] $topUsers
|
||||||
|
*/
|
||||||
|
public function topUsersChart(array $topUsers): Highchart
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
foreach ($topUsers as $topUser) {
|
||||||
|
$data[$topUser->login] = $topUser->subscribersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createChart('bar', $data, 'Top users', 'amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see https://github.com/ghunti/HighchartsPHP/blob/master/demos/highcharts/line/basic_line.php */
|
||||||
|
private function createChart(
|
||||||
|
string $type,
|
||||||
|
array $data,
|
||||||
|
string $bottomLabel,
|
||||||
|
string $amountLabel,
|
||||||
|
): Highchart {
|
||||||
|
$c = new Highchart();
|
||||||
|
|
||||||
|
$c->chart->type = $type;
|
||||||
|
|
||||||
|
$c->title->text = $this->translator->trans($bottomLabel);
|
||||||
|
|
||||||
|
// Preparing chart data
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$chartData['keys'][] = $key;
|
||||||
|
$chartData['values'][] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$c->xAxis->title = ['text' => null];
|
||||||
|
$c->xAxis->categories = $chartData['keys'] ?? [];
|
||||||
|
|
||||||
|
$c->yAxis->title->text = $this->translator->trans($amountLabel);
|
||||||
|
$c->yAxis->plotOptions->bar->dataLabels->enabled = true;
|
||||||
|
|
||||||
|
$c->series[] = [
|
||||||
|
'name' => $this->translator->trans($amountLabel),
|
||||||
|
'data' => $chartData['values'] ?? [],
|
||||||
|
];
|
||||||
|
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
}
|
26
src/Controller/StatsController.php
Normal file
26
src/Controller/StatsController.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Chart\ChartGenerator;
|
||||||
|
use App\Repository\{SubscriptionEventRepository, UserRepository};
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class StatsController extends AbstractController
|
||||||
|
{
|
||||||
|
public function show(
|
||||||
|
UserRepository $userRepository,
|
||||||
|
SubscriptionEventRepository $subscriptionEventRepository,
|
||||||
|
ChartGenerator $chartGenerator,
|
||||||
|
): Response {
|
||||||
|
$topUsers = $userRepository->getTopUsersBySubscribersCount();
|
||||||
|
$eventsByDay = $subscriptionEventRepository->getLastEventsByDay();
|
||||||
|
|
||||||
|
return $this->render('Web/User/top.html.twig', [
|
||||||
|
'events_dynamic_chat' => $chartGenerator->eventsDynamicChart($eventsByDay),
|
||||||
|
'top_chart' => $chartGenerator->topUsersChart($topUsers),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,29 +3,21 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\DTO\{TopUserDTO, DailyEventsDTO};
|
|
||||||
use Knp\Component\Pager\PaginatorInterface;
|
|
||||||
use Ob\HighchartsBundle\Highcharts\Highchart;
|
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Repository\{SubscriptionEventRepository, UserRenameEventRepository, UserRepository};
|
use App\Repository\{SubscriptionEventRepository, UserRenameEventRepository, UserRepository};
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\{Request, Response};
|
use Symfony\Component\HttpFoundation\{Request, Response};
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
|
|
||||||
class UserController extends AbstractController
|
class UserController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
private readonly TranslatorInterface $translator,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function show(
|
public function show(
|
||||||
Request $request,
|
Request $request,
|
||||||
string $login,
|
string $login,
|
||||||
SubscriptionEventRepository $subscriptionEventRepository,
|
SubscriptionEventRepository $subscriptionEventRepository,
|
||||||
UserRepository $userRepository,
|
UserRepository $userRepository,
|
||||||
UserRenameEventRepository $renameEventRepository,
|
UserRenameEventRepository $renameEventRepository,
|
||||||
PaginatorInterface $paginator
|
PaginatorInterface $paginator,
|
||||||
): Response {
|
): Response {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = $userRepository->findUserByLogin($login);
|
$user = $userRepository->findUserByLogin($login);
|
||||||
|
@ -37,7 +29,7 @@ class UserController extends AbstractController
|
||||||
$subscriberEventsPagination = $paginator->paginate(
|
$subscriberEventsPagination = $paginator->paginate(
|
||||||
$subscriptionEventRepository->createUserLastSubscribersEventsQuery($user),
|
$subscriptionEventRepository->createUserLastSubscribersEventsQuery($user),
|
||||||
$request->query->getInt('page', 1),
|
$request->query->getInt('page', 1),
|
||||||
10
|
10,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->render('Web/User/show.html.twig', [
|
return $this->render('Web/User/show.html.twig', [
|
||||||
|
@ -47,84 +39,4 @@ class UserController extends AbstractController
|
||||||
'rename_log' => $renameEventRepository->findBy(['user' => $user], ['date' => 'DESC'], 10),
|
'rename_log' => $renameEventRepository->findBy(['user' => $user], ['date' => 'DESC'], 10),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function top(UserRepository $userRepository, SubscriptionEventRepository $subscriptionEventRepository): Response
|
|
||||||
{
|
|
||||||
$topUsers = $userRepository->getTopUsers();
|
|
||||||
$eventsByDay = $subscriptionEventRepository->getLastEventsByDay();
|
|
||||||
|
|
||||||
return $this->render('Web/User/top.html.twig', [
|
|
||||||
'events_dynamic_chat' => $this->createEventsDynamicChart($eventsByDay),
|
|
||||||
'top_chart' => $this->createTopUsersGraph($topUsers),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param DailyEventsDTO[] $eventsByDay
|
|
||||||
*@todo move to the service
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private function createEventsDynamicChart(array $eventsByDay = []): Highchart
|
|
||||||
{
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
foreach ($eventsByDay as $dailyEvents) {
|
|
||||||
$data[$dailyEvents->date->format('d.m')] = $dailyEvents->eventsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createChart('eventschart', 'line', $data, 'Events by day', 'amount');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo move to the service
|
|
||||||
*
|
|
||||||
* @param TopUserDTO[] $topUsers
|
|
||||||
*/
|
|
||||||
private function createTopUsersGraph(array $topUsers = []): Highchart
|
|
||||||
{
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
foreach ($topUsers as $topUser) {
|
|
||||||
$data[$topUser->login] = $topUser->subscribersCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createChart('topchart', 'bar', $data, 'Top users', 'amount');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createChart(string $blockId, string $type, array $data, string $bottomLabel, string $amountLabel): Highchart
|
|
||||||
{
|
|
||||||
$chartData = [
|
|
||||||
'keys' => [],
|
|
||||||
'values' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Preparing chart data
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
$chartData['keys'][] = $key;
|
|
||||||
$chartData['values'][] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chart
|
|
||||||
$series = [[
|
|
||||||
'name' => $this->translator->trans($amountLabel),
|
|
||||||
'data' => $chartData['values'],
|
|
||||||
]];
|
|
||||||
|
|
||||||
// Initializing chart
|
|
||||||
$ob = new Highchart();
|
|
||||||
$ob->chart->renderTo($blockId);
|
|
||||||
$ob->chart->type($type);
|
|
||||||
$ob->title->text($this->translator->trans($bottomLabel));
|
|
||||||
$ob->xAxis->title(['text' => null]);
|
|
||||||
$ob->xAxis->categories($chartData['keys']);
|
|
||||||
$ob->yAxis->title(['text' => $this->translator->trans($amountLabel)]);
|
|
||||||
$ob->plotOptions->bar([
|
|
||||||
'dataLabels' => [
|
|
||||||
'enabled' => true
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
$ob->series($series);
|
|
||||||
|
|
||||||
return $ob;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ declare(strict_types=1);
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\DTO\DailyEventsDTO;
|
use App\DTO\DailyEventsDTO;
|
||||||
use App\Entity\SubscriptionEvent;
|
use App\Entity\{SubscriptionEvent, User};
|
||||||
use App\Entity\User;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
@ -63,11 +62,7 @@ class SubscriptionEventRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return list<SubscriptionEvent> */
|
||||||
* Get last user subscriber events
|
|
||||||
*
|
|
||||||
* @return SubscriptionEvent[]
|
|
||||||
*/
|
|
||||||
public function getUserLastSubscribersEvents(User $user, int $limit = 20): array
|
public function getUserLastSubscribersEvents(User $user, int $limit = 20): array
|
||||||
{
|
{
|
||||||
$qb = $this->createUserLastSubscribersEventsQuery($user);
|
$qb = $this->createUserLastSubscribersEventsQuery($user);
|
||||||
|
@ -89,11 +84,7 @@ class SubscriptionEventRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return SubscriptionEvent[] */
|
||||||
* Get last global subscription events
|
|
||||||
*
|
|
||||||
* @return SubscriptionEvent[]
|
|
||||||
*/
|
|
||||||
public function getLastSubscriptionEvents(int $limit = 20): array
|
public function getLastSubscriptionEvents(int $limit = 20): array
|
||||||
{
|
{
|
||||||
$qb = $this->createLastSubscriptionEventsQuery();
|
$qb = $this->createLastSubscriptionEventsQuery();
|
||||||
|
|
|
@ -4,8 +4,7 @@ declare(strict_types=1);
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\DTO\TopUserDTO;
|
use App\DTO\TopUserDTO;
|
||||||
use App\Entity\Subscription;
|
use App\Entity\{Subscription, User};
|
||||||
use App\Entity\User;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
@ -108,12 +107,8 @@ class UserRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return list<TopUserDTO> */
|
||||||
* Returns top users by subscribers count
|
public function getTopUsersBySubscribersCount(int $limit = 30): array
|
||||||
*
|
|
||||||
* @return TopUserDTO[]
|
|
||||||
*/
|
|
||||||
public function getTopUsers(int $limit = 30): array
|
|
||||||
{
|
{
|
||||||
$qb = $this->getEntityManager()->getRepository(Subscription::class)->createQueryBuilder('s');
|
$qb = $this->getEntityManager()->getRepository(Subscription::class)->createQueryBuilder('s');
|
||||||
|
|
||||||
|
|
46
src/Twig/HighchartExtension.php
Normal file
46
src/Twig/HighchartExtension.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Twig;
|
||||||
|
|
||||||
|
use Ghunti\HighchartsPHP\Highchart;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\{TwigFilter, TwigFunction};
|
||||||
|
|
||||||
|
class HighchartExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
public function getFilters(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFilter('hc_scripts', [$this, 'printScripts'], ['is_safe' => ['html']]),
|
||||||
|
new TwigFilter('hc_render', [$this, 'render'], ['is_safe' => ['html']]),
|
||||||
|
new TwigFilter('hc_options', [$this, 'renderOptions'], ['is_safe' => ['html']]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFunctions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFunction('hc_scripts', [$this, 'printScripts'], ['is_safe' => ['html']]),
|
||||||
|
new TwigFunction('hc_render', [$this, 'render'], ['is_safe' => ['html']]),
|
||||||
|
new TwigFunction('hc_options', [$this, 'renderOptions'], ['is_safe' => ['html']]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function printScripts(Highchart $c): string
|
||||||
|
{
|
||||||
|
return $c->printScripts(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(Highchart $c, string $blockId, ?string $varName = null, bool $withScriptTag = false): string
|
||||||
|
{
|
||||||
|
$c->chart->renderTo = $blockId;
|
||||||
|
|
||||||
|
return $c->render($varName, withScriptTag: $withScriptTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderOptions(Highchart $c): string
|
||||||
|
{
|
||||||
|
return $c->renderOptions();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,14 +9,13 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<script type="text/javascript">
|
|
||||||
// Top chart
|
|
||||||
{{ chart(top_chart) }}
|
|
||||||
// Events by day chart
|
|
||||||
{{ chart(events_dynamic_chat) }}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="topchart" style="min-width: 400px; height: 600px; margin: 0 auto;"></div>
|
<div id="topchart" style="min-width: 400px; height: 600px; margin: 0 auto;"></div>
|
||||||
|
|
||||||
<div id="eventschart" style="min-width: 400px; height: 600px; margin: 0 auto;"></div>
|
<div id="eventschart" style="min-width: 400px; height: 600px; margin: 0 auto;"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
{{ top_chart | hc_render('topchart') }}
|
||||||
|
{{ events_dynamic_chat | hc_render('eventschart') }}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue