Highcharts — библиотека для создания графиков написанная на JavaScript, позволяет легко добавлять интерактивные, анимированные графики на сайт или в веб-приложение. На данный момент графики поддерживают большое количество диаграмм линейных, круговых, колоночных рассеивающих и многих других типов.
Графики работают со всеми популярными браузерами, включая Safari на iPhone.
В этой статье мы рассмотрим простой вариант использования графика изменения соотношения стоимости пары Usd/Eur. Я рассчитываю, что у вас уже есть установленный и настроенный Laravel.
p.s. Статья получилась с сильным уклоном на backend чем на frontend, т.к. по ссылке выше можно легко копипастнуть код вывода графиков. Но получение данных, там не описано
А начнем мы с описания нашей задачи.
В первую очередь, нам необходимо иметь возможность получать информацию о котировках валют. Для этого мы можем использовать данные из файла, брать данные по сети, из базы данных или как либо еще. Например, из мемкеша. Затем нам необходимо будет обработать эти данные и отдать в представление для показа пользователю.
Во-вторых, наши графики могут строиться не только в одном конкретном контроллере, но и в разных частях нашего приложения. Потому, чтобы не дублировать один и тот же код и соблюдать принципы DRY, получение данных валют мы вынесем в отдельное абстрактное место. В отдельный класс – репозиторий.
Для начала, давайте опишем интерфейс нашего репозитория. Создадим новый файл контракта:
<?php
declare(strict_types=1);
namespace App\Contracts;
use Illuminate\Support\Collection;
interface ExchangeRateRepositoryContract
{
public function getData(): Collection;
}
Судя по этому интерфейсу, все наши репозитории обязаны будут иметь метод getData, который возвращает нам некую коллекцию.
Создадим наш первый репозиторий:
<?php
declare(strict_types=1);
namespace App\Repositories;
use App\Contracts\ExchangeRateRepositoryContract;
use Illuminate\Support\Collection;
class ExchangeRatesFromUrlRepository implements ExchangeRateRepositoryContract
{
public function getData(): Collection
{
$data = file_get_contents('https://cdn.jsdelivr.net/gh/highcharts/highcharts@v7.0.0/samples/data/usdeur.json');
$json = json_decode($data, true);
return new Collection($json);
}
}
Все довольно просто. Данный репозиторий, как следует из его названия, берет данные по какому-то url, декодирует как-то и возвращает нам коллекцию.
В файле AppServiceProvider.php забиндим текущий контракт с нашей реализацией
public function register()
{
$this->app->bind(ExchangeRateRepositoryContract::class, ExchangeRatesFromUrlRepository::class);
}
Теперь давайте создадим новый контроллер, назовем его ChartController:
sail artisan make:controller ChartController
и пропишем ему зависимости в конструкторе
<?php
namespace App\Http\Controllers;
use App\Contracts\ExchangeRateRepositoryContract;
use Illuminate\Http\Request;
class ChartController extends Controller
{
private ExchangeRateRepositoryContract $exchangeRateRepository;
public function __construct(ExchangeRateRepositoryContract $exchangeRateRepository)
{
$this->exchangeRateRepository = $exchangeRateRepository;
}
public function index(Request $request)
{
$data = json_encode($this->exchangeRateRepository->getData()->toArray());
return view('chart.index' , compact('data'));
}
}
В методе index нам необходимо получить данные из нашего репозитория, конвертировать в json и передать в представление.
В самом представлении нам понадобятся библиотеки самого Highcharts
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
контейнер для графика
<div id="container"></div>
ну и сам код графика. Пример взят со страницы демо
Highcharts.chart('container', {
title: {
text: 'USD to EUR exchange rate over time'
},
xAxis: {
type: 'datetime'
},
yAxis: {
title: {
text: 'Exchange rate'
}
},
series: [{
type: 'area',
name: 'USD to EUR',
data: {{ $data }}
}]
});
Теперь можно посмотреть, что у нас получилось:

На следующий день, мы узнаем, что путь, по которому мы получали данные больше не существует. Нагрузка от нас на сервер оказалась высокой и нас попросили так больше не делать. Что делать? Пишем крон задачу, которая раз в сутки будет запрашивать данные с удаленного сервера и записывать данные в файл.
Затем создадим новый репозиторий, который будет читать уже из файла:
<?php
declare(strict_types=1);
namespace App\Repositories;
use App\Contracts\ExchangeRateRepositoryContract;
use Illuminate\Support\Collection;
class ExchangeRatesFromFileRepository implements ExchangeRateRepositoryContract
{
public function getData(): Collection
{
$filePath = storage_path('app/data.json');
$data = file_get_contents($filePath);
$json = json_decode($data, true);
return new Collection($json);
}
}
и в сервис провайдере лишь заменим строчку c ExchangeRatesFromUrlRepository
на ExchangeRatesFromFileRepository
public function register()
{
$this->app->bind(ExchangeRateRepositoryContract::class, ExchangeRatesFromFileRepository::class);
}
Так как в контроллерах мы сделали связь на интерфейс, то править там ничего не придется. Строчка выше автоматически применится ко всем контроллерам, которые запрашивают данный контракт ExchangeRateRepositoryContract
. Такой подход описан в принципе Открытости/Закрытости в SOLID
Если однажды, вам потребуется получать данные из бд, вы просто напишете новый репозиторий ExchangeRatesFromDbRepository
, опишите в нем новую логику получения данных и поменяете строчку в AppServiceProvider