Урок 12. Рендеринг диаграмм в приложениях Laravel


Все уроки по Laravel расположены здесь

Люди говорят, что картина стоит тысячи слов. Это также верно и для диаграмм, которые дают возможность сжать огромные объемы данных в вид, легко понимаемый человеком. В этой статье мы обсудим, как визуализировать диаграммы в приложении Laravel. Подход, который мы будем использовать, не требует установки дополнительных библиотек; визуализация диаграмм будет простой и быстрой.

Что мы будем строить

Пример страницы отчета с диаграммами
Пример страницы отчета с диаграммами

Давайте представим, что мы создаем страницу отчета для интернет-магазина. Этот отчет может содержать:

  • Заказов в месяц — Количество заказов, размещенных клиентами в месяц
  • Ежемесячный доход — Сумма дохода, полученного в месяц
  • Доля товаров — Список самых продаваемых товаров за определенный период
Доступ к отчету осуществляется в виде веб-страницы на сайте Laravel.

Выбор технологии

В Laravel существует несколько подходов к рендерингу диаграмм. Например, с помощью интерфейсной библиотеки JavaScript, такой как Chart.js, Highcharts или Vega-Lite. Однако у этого есть недостаток-включение рассматриваемой библиотеки во внешний интерфейс. Для клиентов, у которых JavaScript деактивирован (например, электронная почта).

Другой подход состоял бы в том, чтобы визуализировать диаграмму на сервере и отправить ее клиенту в виде изображения. В этом пространстве нет большой конкуренции. Один из вариантов, который я могу найти,- это c-pchart, который, к сожалению, кажется слишком многословным на мой вкус. Недостатком рендеринга диаграммы на сервере является повышенная вычислительная мощность, необходимая для сервера. Рендеринг диаграмм не так дешев, как типичная рабочая нагрузка сервера (получение данных из БД, преобразование и т. д.).

Другой подход заключается в использовании GetChart.me для визуализации диаграмм. Короче говоря, GetChart.me это сервис, который позволяет нам получить изображение диаграммы из определения диаграммы, закодированного в URL-адресе. Это означает, что встраивание изображения в HTML-страницу так же просто, как <img src="{url}"/>. Недостатком такого подхода является зависимость от внешней службы, что означает, что доступность изображений диаграмм зависит от доступности самой службы.

В этой статье мы рассмотрим GetChart.me по следующим причинам:

  • Начать работу легко и быстро — просто создайте URL-адрес и вставьте его в виде изображения в HTML-документ.
  • Нет JavaScript — Графики могут охватывать больше клиентов (например, электронные письма).
  • Использует open source chart definition (Vega-Lite) — Если сервис не работает, мы можем вернуться к подходу “клиентская библиотека”, добавив Vega-Lite на HTML-страницу.
Настройка шаблона блейда

Во-первых, давайте создадим новый шаблон блейда с именем report.blade.php в папке resource/views. Как следует из названия, этот шаблон будет отображать страницу отчета. Содержание шаблона выглядит следующим образом:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Отчеты</title>

        <!-- Fonts -->
        <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">

        <!-- Styles -->
        <style>
            body {
                font-family: 'Nunito';
                max-width: 600px;
                margin: auto;
            }
            img {
                max-width: 100%
            }
        </style>
    </head>
    <body>
        <h1>Отчеты</h1>

        <h2>Заказов в месяц</h1>
        <img src="{{ $monthlyOrdersImageUrl }}" />

        <h2>Ежемесячный доход</h2>
        <img src="{{ $monthlyRevenueImageUrl }}" />

        <h2>Доля продуктов</h2>
        <img src="{{ $shareOfProductsImageUrl }}" />
    </body>
</html>
Здесь нет ничего особенного. Как вы можете видеть, диаграммы в основном представляют собой изображения, указывающие на некоторые URL-адреса. URL-адреса будут передаваться из контроллера через три параметра шаблона: monthlyOrdersImageUrl, monthlyRevenuaImageUrl и shareOfProductsImageUrl.

Создание контроллера и подключение блейд-шаблона

Создайте новый файл с именем ReportController.php папка in app/Http/Controllers. Поместите следующий код в файл:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;

class ReportController extends Controller
{
    public function show()
    {
        return view('report', [
            'monthlyOrdersImageUrl' => $this->monthlyOrdersImageUrl(),
            'monthlyRevenueImageUrl' => $this->monthlyRevenueImageUrl(),
            'shareOfProductsImageUrl' => $this->shareOfProductsImageUrl(),
        ]);
    }

    private function monthlyOrdersImageUrl() {
		return "";
    }

    private function monthlyRevenueImageUrl() {
		return "";
    }

    private function shareOfProductsImageUrl() {
		return "";
    }
}
Из исходного кода мы подключаем шаблон, созданный ранее с помощью view('report', ...). Мы также передаем три переменные шаблона, хотя на данный момент все они являются пустыми строками.

GetChart.me вспомогательная функция URL

Прежде чем сделать фактическую диаграмму, давайте создадим вспомогательную функцию для генерации GetChart.me URL. GetChart.me работает путем отправки URL-кодированного определения диаграммы Vega-Lite в качестве параметра URL.



В PHP мы реализуем его как простую однострочную строку, подобную этой:

private function buildGetChartMeUrl($chart) {
	return "https://pub.getchart.me/vega-lite?c=" . urlencode(json_encode($chart));
}
Эта функция получает определение диаграммы Vega-Lite (в PHP maps) и выводит действительное GetChart.me URL.

Создание диаграммы

Создание диаграммы включает в себя две вещи:

  • Определение того, как будет выглядеть диаграмма.
  • Определение данных для диаграммы.
Данные для диаграммы могут поступать откуда угодно. База данных - это типичный источник данных. В этой статье мы просто жестко закодируем данные для краткости.

Определение визуальных элементов диаграммы - это в основном то же самое, что и написание определения диаграммы Vega-Lite. В примерах Vega-Lite есть множество графиков. Документация библиотеки тоже довольно солидная. В нашем случае мы используем гистограмму, линейную диаграмму и горизонтальную гистограмму.

Код для создания диаграмм выглядит следующим образом:

private function monthlyOrdersImageUrl() {
        $data = [
            [ "date" => "2021-01-01", "Orders" => 21 ],
            [ "date" => "2021-02-01", "Orders" => 46 ],
            [ "date" => "2021-03-01", "Orders" => 66 ],
            [ "date" => "2021-04-01", "Orders" => 81 ],
            [ "date" => "2021-05-01", "Orders" => 99 ],
            [ "date" => "2021-06-01", "Orders" => 117 ],
        ];
        $chart = [
            "data" => [ "values" => $data ],
            "width" => 450,
            "height" => 300,
            "layer" => [
                [
                    "encoding" => [
                        "x" => [
                            "field" => "date",
                            "type" => "ordinal",
                            "timeUnit" => "month",
                            "axis" => [ "labelAngle" => 0 ],
                            "title" => "Month"
                        ],
                        "y" => [
                            "field" => "Orders",
                            "type" => "quantitative"
                        ]
                    ],
                    "layer" => [
                        [ "mark" => [ "type" => "bar" ] ],
                        [
                            "mark" => ["type" => "text", "dy" => -8],
                            "encoding" => ["text" => ["field" => "Orders", "type" => "quantitative" ]]
                        ]
                    ]
                ]
            ]
        ];
        return $this->buildGetChartMeUrl($chart);
    }

    private function monthlyRevenueImageUrl() {
        $data = [
            [ "date" => "2021-01-01", "Revenue" => 2123 ],
            [ "date" => "2021-02-01", "Revenue" => 4656 ],
            [ "date" => "2021-03-01", "Revenue" => 6652 ],
            [ "date" => "2021-04-01", "Revenue" => 8132 ],
            [ "date" => "2021-05-01", "Revenue" => 9992 ],
            [ "date" => "2021-06-01", "Revenue" => 11768 ],
        ];
        $chart = [
            "data" => [ "values" => $data ],
            "width" => 450,
            "height" => 300,
            "layer" => [
                [
                    "encoding" => [
                        "x" => [
                            "field" => "date",
                            "type" => "ordinal",
                            "timeUnit" => "month",
                            "axis" => [ "labelAngle" => 0 ],
                            "title" => "Month"
                        ],
                        "y" => [
                            "field" => "Revenue",
                            "type" => "quantitative"
                        ]
                    ],
                    "layer" => [
                        [ "mark" => [ "type" => "line", "point" => true ] ],
                        [
                            "mark" => ["type" => "text", "align" => "left", "dx" => 8, "dy" => 8],
                            "encoding" => ["text" => ["field" => "Revenue", "type" => "quantitative" ]]
                        ]
                    ]
                ]
            ]
        ];
        return $this->buildGetChartMeUrl($chart);
    }

    private function shareOfProductsImageUrl() {
        $data = [
            [ "Product" => "Apple", "Orders" => 21 ],
            [ "Product" => "Orange", "Orders" => 46 ],
            [ "Product" => "Banana", "Orders" => 123 ],
            [ "Product" => "Guava", "Orders" => 34 ],
            [ "Product" => "Dragonfruit", "Orders" => 65 ],
            [ "Product" => "Jackfruit", "Orders" => 117 ],
        ];
        $chart = [
            "data" => [ "values" => $data ],
            "width" => 450,
            "height" => 300,
            "layer" => [
                [
                    "encoding" => [
                        "y" => [
                            "field" => "Product",
                            "type" => "nominal",
                            "sort" => "-x"
                        ],
                        "x" => [
                            "field" => "Orders",
                            "type" => "quantitative"
                        ]
                    ],
                    "layer" => [
                        [ "mark" => [ "type" => "bar" ] ],
                        [
                            "mark" => ["type" => "text", "dx" => 8, "align" => "left"],
                            "encoding" => ["text" => ["field" => "Orders", "type" => "quantitative" ]]
                        ]
                    ]
                ]
            ]
        ];
        return $this->buildGetChartMeUrl($chart);
    }
Замените функции в классе ReportController на соотвествующие выше. Не забудьте также в фале роутинга сделать перенаправление:

use App\Http\Controllers\ReportController;

..

Route::get('/report', [ReportController::class, 'show']);
Обновите страницу. Вы должны видеть, что страница отчета теперь с диаграммами. Если вы успешно достигли этой точки, то мы закончили. Довольно просто, правда?

Вывод

В этой статье мы создали страницу отчета, содержащую диаграммы в Laravel. Существуют различные способы визуализации диаграмм в приложении Laravel: с помощью клиентской библиотеки диаграмм, серверного рендеринга диаграмм или стороннего сервиса рендеринга диаграмм (GetChart.me). В этой статье мы рассмотрели GetChart.me из-за его низкой сложности и портативности.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, уроки по Laravel, диаграммы, php, графики




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Гарантия на парсинг
Личный опыт парсинга pdf с помощью PHP
Пара слов о серии "Плоский мир"