Создание виджета (руководство)

Это пошаговое руководство, показывает, как создать простой виджет панели.

Минимальная необходимая версия Zabbix для этого руководства — 6.4.4.

Вы можете загрузить все файлы этого виджета в виде ZIP-архива: lesson_gauge_chart.zip.

Что вы будете создавать

В ходе этого урока вы сначала создадите базовый "Hello, world!" виджет, а затем преобразуйте его в виджет более продвинутый, который отображает значение элемента в виде диаграммы. Вот как будет выглядеть готовый виджет:

Часть I - "Привет, мир!"

В этом разделе вы изучите, как создать минимально необходимые элементы виджета и добавить новый виджет в веб-интерфейс Zabbix.

Добавление пустого виджета в веб-интерфейс Zabbix

  1. Создайте каталог lesson_gauge_chart в каталоге modules вашей установки веб-интерфейса Zabbix (например, zabbix/ui/modules).

Все пользовательские виджеты рассматриваются как внешние модули и должны быть добавлены в каталог modules вашей установки веб-интерфейса Zabbix (например, zabbix/ui/modules). Каталог zabbix/ui/widgets зарезервирован для встроенных виджетов Zabbix и обновляется вместе с пользовательским интерфейсом Zabbix.

  1. Создайте файл manifest.json с основными метаданными виджета (см. описание поддерживаемых параметров).

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.1",
           "author": "Zabbix"
       }
  1. В интерфейсе Zabbix перейдите в раздел Администрирование → Общие → Модули и нажмите кнопку Сканировать каталог.

  1. Найдите новый модуль Диаграмма измерений в списке и нажмите гиперссылку "Отключено", чтобы изменить статус модуля с "Отключено" на "Включено".

  1. Откройте дашборд, переведите его в режим редактирования и добавьте новый виджет. В поле Тип выберите "Датчик диаграммы".

  1. На данный момент конфигурация виджета Диаграмма содержит только общие поля виджета Имя и Интервал обновления. Нажмите Добавить, чтобы добавить виджет на панель.

  1. На панели инструментов должен появиться пустой виджет. Нажмите Сохранить изменения в правом верхнем углу, чтобы сохранить панель.

Добавление представления виджета

Файл view виджета должен находиться в каталоге views (для этого руководства ui/modules/lesson_gauge_chart/views/). Если файл имеет имя по умолчанию widget.view.php, вам не нужно регистрировать его в файле manifest.json. Если файл имеет другое имя, укажите его в разделе actions/widget.lesson_gauge_chart.view файла manifest.json.

  1. Создайте каталог views в каталоге lesson_gauge_chart.

  2. Создайте файл widget.view.php в каталоге views.

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem(
               new CTag('h1', true, 'Hello, world!')
           )
           ->show();
  1. Обновите панель мониторинга. Виджет Диаграмма теперь отображает надпись "Привет, мир!".

Часть II - Диаграмма измерений

Добавление настройки в представление конфигурации и использование их в представлении виджетов

В этом разделе вы узнаете, как добавить поле конфигурации виджета и отобразить введенное значение в представлении виджета в виде текста.

Конфигурация виджета состоит из формы (Zabbix\Widgets\CWidgetForm) и представления формы виджета (widget.edit.php). Чтобы добавить поля (Zabbix\Widgets\CWidgetField), вам необходимо создать класс WidgetForm, который будет расширять Zabbix\Widgets\CWidgetForm.

Форма содержит набор полей (Zabbix\Widgets\CWidgetField) различных типов, которые используются для проверки введенных пользователем значений. Поле формы (Zabbix\Widgets\CWidgetField) для каждого типа входного элемента преобразует значение в единый формат для сохранения его в базе данных.

Файл form виджета должен находиться в каталоге includes (в данном руководстве ui/modules/lesson_gauge_chart/includes/). Если файл имеет имя по умолчанию WidgetForm.php, вам не нужно регистрировать его в файле manifest.json. Если файл имеет другое имя, укажите его в разделе widget/form_class файла manifest.json.

  1. Создайте новый каталог includes в каталоге lesson_gauge_chart.

  2. Создайте файл WidgetForm.php в каталоге includes.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\CWidgetForm;
       
       class WidgetForm extends CWidgetForm {
       }
  1. Добавьте поле Описание в форму настройки виджета. Это обычное текстовое поле, в которое пользователь может ввести любой набор символов. Для этого вы можете использовать класс CWidgetFieldTextBox.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\CWidgetForm;
       
       use Zabbix\Widgets\Fields\CWidgetFieldTextBox;
       
       class WidgetForm extends CWidgetForm {
       
           public function addFields(): self {
               return $this
                   ->addField(
                      new CWidgetFieldTextBox('description', _('Description'))
                   );
          }
       }
  1. В каталоге views создайте файл представления конфигурации виджета widget.edit.php и добавьте представление для нового поля Description. Для класса поля CWidgetFieldTextBox представлением является CWidgetFieldTextBoxView.

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Просмотр виджета диаграммы с указателем.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetFormView($data))
           ->addField(
               new CWidgetFieldTextBoxView($data['fields']['description'])
           )
           ->show();
  1. Перейдите на панель и нажмите на значок шестеренки в виджете, чтобы открыть форму настройки виджета.

  2. Форма настройки виджета теперь содержит новое текстовое поле Описание. Введите любое значение, например Описание диаграммы датчиков.

  1. Нажмите Применить в форме настройки виджета. Затем нажмите Сохранить изменения в правом верхнем углу, чтобы сохранить панель. Обратите внимание, что новое описание нигде не видно, а виджет по-прежнему отображает "Привет, мир!".

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

  1. Создайте новый каталог actions в каталоге lesson_gauge_chart.

  2. Создайте файл WidgetView.php в каталоге actions. Класс действия WidgetView расширит класс CControllerDashboardWidgetView.

Значения полей конфигурации виджета хранятся в свойстве $fields_values класса действия.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
               $this->setResponse(new CControllerResponseData([
                   'name' => $this->getInput('name', $this->widget->getName()),
                   'description' => $this->fields_values['description'],
                   'user' => [
                       'debug_mode' => $this->getDebugMode()
                   ]
               ]));
           }
       }
  1. Откройте manifest.json и зарегистрируйте WidgetView как класс действия в разделе actions/widget.lesson_gauge_chart.view.

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix",
           "actions": {
               "widget.lesson_gauge_chart.view": {
                   "class": "WidgetView"
               }
           }
       }
  1. Теперь вы можете использовать значение поля описания, содержащееся в $data['description'], в представлении виджета. Откройте views/widget.view.php и замените статический текст "Привет, мир!" с $data['description'].

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Просмотр виджета диаграммы с указателем.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem(
               new CTag('h1', true, $data['description'])
           )
           ->show();
  1. Обновите страницу панели. Теперь вы должны увидеть текст описания виджета вместо "Привет, мир!".

Получение значения элемента данных через API

Виджет должен отображать последнее значение элемента данных по выбору пользователя. Для этого вам необходимо добавить возможность выбора элементов данных в конфигурации виджета.

В этом разделе вы узнаете, как добавить поле выбора элемента данных в форму виджета и как добавить визуальную часть этого поля в представление конфигурации. Затем контроллер виджета сможет получать данные элемента данных и его значение через запрос API. После получения значение можно отобразить в представлении виджета.

  1. Откройте includes/WidgetForm.php и добавьте поле CWidgetFieldMultiSelectItem. Это позволит выбрать элемент данных в форме конфигурации.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Zabbix\Widgets\{
           CWidgetField,
           CWidgetForm
       };
       
       use Zabbix\Widgets\Fields\{
           CWidgetFieldMultiSelectItem,
           CWidgetFieldTextBox
       };
       
       /**
        * Gauge chart widget form.
        */
       class WidgetForm extends CWidgetForm {
           
           public function addFields(): self {
               return $this
                   ->addField(
                       (new CWidgetFieldMultiSelectItem('itemid', _('Item')))
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                           ->setMultiple(false)
                   )
                   ->addField(
                       new CWidgetFieldTextBox('description', _('Description'))
                   );
           }
       }
  1. Откройте views/widget.edit.php и добавьте визуальный компонент поля в представление конфигурации.

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetFormView($data))
           ->addField(
               new CWidgetFieldMultiSelectItemView($data['fields']['itemid'])
           )
           ->addField(
               new CWidgetFieldTextBoxView($data['fields']['description'])
           )
           ->show();
  1. Вернитесь на панель и нажмите на значок шестеренки в виджете, чтобы открыть форму настройки виджета.

  2. Форма настройки виджета теперь содержит новое поле ввода Элемент данных. Выбираем хост "Сервер Zabbix" и пункт "Средняя нагрузка (1м в среднем)".

  1. Нажмите Применить в форме настройки виджета. Затем нажмите Сохранить изменения в правом верхнем углу, чтобы сохранить панель.

  2. Откройте и измените actions/WidgetView.php.

С этого момента идентификатор элемента данных будет доступен в контроллере виджета в $this->fields_values['itemid']. Метод контроллера doAction() собирает данные элемента (имя, тип значения, единицы измерения) с помощью метода API item.get и последнее значение элемента данных с помощью Метод API history.get.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use API,
           CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
               $db_items = API::Item()->get([
                   'output' => ['itemid', 'value_type', 'name', 'units'],
                   'itemids' => $this->fields_values['itemid'],
                   'webitems' => true,
                   'filter' => [
                       'value_type' => [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT]
                   ]
               ]);
       
               $value = null;
       
               if ($db_items) {
                   $item = $db_items[0];
       
                   $history = API::History()->get([
                       'output' => API_OUTPUT_EXTEND,
                       'itemids' => $item['itemid'],
                       'history' => $item['value_type'],
                       'sortfield' => 'clock',
                       'sortorder' => ZBX_SORT_DOWN,
                       'limit' => 1
                   ]);
       
                   if ($history) {
                       $value = convertUnitsRaw([
                           'value' => $history[0]['value'],
                           'units' => $item['units']
                       ]);
                   }
               }
       
               $this->setResponse(new CControllerResponseData([
                   'name' => $this->getInput('name', $this->widget->getName()),
                   'value' => $value,
                   'description' => $this->fields_values['description'],
                   'user' => [
                       'debug_mode' => $this->getDebugMode()
                   ]
               ]));
           }
       }
  1. Откройте views/widget.view.php и добавьте значение элемента данных в представление виджета.

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem([
               new CTag('h1', true, $data['description']),
               new CDiv($data['value'] !== null ? $data['value']['value'] : _('No data'))
           ])
           ->show();
  1. Обновите страницу панели. Виджет отобразит последнее значение элемента данных.

Добавление JavaScript в виджет

В этом разделе вы узнаете, как добавить элементы JavaScript в виджет.

Вы добавите:

  • Индикаторный график, созданный с помощью JavaScript, чтобы сразу показать, является ли последнее значение нормальным или слишком высоким/низким.
  • Раздел Расширенная конфигурация для дополнительных параметров, таких как цвет, минимальные и максимальные значения, единицы измерения и поле Описание, созданное ранее.
  1. Создайте файл widget.edit.js.php в каталоге views.

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

Поскольку JavaScript для представления конфигурации должен загружаться вместе с формой, вам нужно будет включить его в файл widget.edit.php, как показано на следующих шагах.

ui/modules/lesson_gauge_chart/views/widget.edit.js.php

<?php
       
       use Modules\LessonGaugeChart\Widget;
       
       ?>
       
       window.widget_lesson_gauge_chart_form = new class {
       
           init({color_palette}) {
               this._form = document.getElementById('widget-dialogue-form');
       
               this._advanced_configuration = document.getElementById('adv_conf');
               this._unit_select = document.getElementById('value_units');
               this._unit_value = document.getElementById('value_static_units');
       
               this._advanced_configuration.addEventListener('change', () => this.updateForm());
               this._unit_select.addEventListener('change', () => this.updateForm());
       
               colorPalette.setThemeColors(color_palette);
       
               for (const colorpicker of jQuery('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) {
                   jQuery(colorpicker).colorpicker();
               }
       
               const overlay = overlays_stack.getById('widget_properties');
       
               for (const event of ['overlay.reload', 'overlay.close']) {
                   overlay.$dialogue[0].addEventListener(event, () => { jQuery.colorpicker('hide'); });
               }
       
               this.updateForm();
           }
       
           updateForm() {
               const show_advanced_configuration = this._advanced_configuration.checked;
       
               for (const element of this._form.querySelectorAll('.js-advanced-configuration')) {
                   element.style.display = show_advanced_configuration ? '' : 'none';
               }
       
               this._unit_value.disabled = this._unit_select.value == <?= Widget::UNIT_AUTO ?>;
           }
       };
  1. Создайте файл Widget.php в основном каталоге виджетов lesson_gauge_chart, чтобы создать новый класс Widget.

Класс Widget расширит базовый класс CWidget, чтобы добавить/переопределить настройки виджета по умолчанию (в данном случае — переводы). JavaScript, представленный ниже, отображает строку "Нет данных" в случае отсутствия данных. Строка "Нет данных" присутствует в файлах перевода Zabbix UI.

Если есть какие-либо константы виджета, рекомендуется также указать их в классе Widget.

ui/modules/lesson_gauge_chart/Widget.php

<?php 
       
       namespace Modules\LessonGaugeChart;
       
       use Zabbix\Core\CWidget;
       
       class Widget extends CWidget {
       
           public const UNIT_AUTO = 0;
           public const UNIT_STATIC = 1;
       
           public function getTranslationStrings(): array {
               return [
                   'class.widget.js' => [
                       'No data' => _('No data')
                   ]
               ];
           }
       }
  1. Откройте includes/WidgetForm.php и добавьте новые поля Color (выбор цвета), Min (числовое поле), Max (числовое поле) и Units (выберите) и определите цветовая палитра по умолчанию для палитры цветов, чтобы ее можно было использовать на следующих шагах.

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php
       
       namespace Modules\LessonGaugeChart\Includes;
       
       use Modules\LessonGaugeChart\Widget;
       
       use Zabbix\Widgets\{
           CWidgetField,
           CWidgetForm
       };
       
       use Zabbix\Widgets\Fields\{
           CWidgetFieldCheckBox,
           CWidgetFieldColor,
           CWidgetFieldMultiSelectItem,
           CWidgetFieldNumericBox,
           CWidgetFieldSelect,
           CWidgetFieldTextBox
       };
       
       /**
        * Gauge chart widget form.
        */
       class WidgetForm extends CWidgetForm {
       
           public function addFields(): self {
               return $this
                   ->addField(
                       (new CWidgetFieldMultiSelectItem('itemid', _('Item')))
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                           ->setMultiple(false)
                           ->setFilterParameter('numeric', true)
                   )
                   ->addField(
                       new CWidgetFieldCheckBox('adv_conf', _('Advanced configuration'))
                   )
                   ->addField(
                       (new CWidgetFieldColor('chart_color', _('Color')))->setDefault('FF0000')
                   )
                   ->addField(
                       (new CWidgetFieldNumericBox('value_min', _('Min')))
                           ->setDefault(0)
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                   )
                   ->addField(
                       (new CWidgetFieldNumericBox('value_max', _('Max')))
                           ->setDefault(100)
                           ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                   )
                   ->addField(
                       (new CWidgetFieldSelect('value_units', _('Units'), [
                           Widget::UNIT_AUTO => _x('Auto', 'history source selection method'),
                           Widget::UNIT_STATIC => _x('Static', 'history source selection method')
                       ]))->setDefault(Widget::UNIT_AUTO)
                   )
                   ->addField(
                       (new CWidgetFieldTextBox('value_static_units'))
                   )
                   ->addField(
                       new CWidgetFieldTextBox('description', _('Description'))
                   );
           }
       }
  1. Откройте views/widget.edit.php и добавьте визуальные компоненты полей в представление конфигурации.

Метод addField() класса CWidgetFormView принимает строку CSS-класса в качестве второго параметра. Добавьте строку js-advanced-configuration к тем полям и их меткам, которые должны быть скрыты, если Расширенная конфигурация не выбрана.

Чтобы добавить JavaScript-файл в представление конфигурации, используйте метод includeJsFile(). Чтобы добавить встроенный JavaScript, используйте метод addJavaScript().

ui/modules/lesson_gauge_chart/views/widget.edit.php

<?php
       
       /**
        * Gauge chart widget form view.
        *
        * @var CView $this
        * @var array $data
        */
       
       use Zabbix\Widgets\Fields\CWidgetFieldGraphDataSet;
       
       $lefty_units = new CWidgetFieldSelectView($data['fields']['value_units']);
       $lefty_static_units = (new CWidgetFieldTextBoxView($data['fields']['value_static_units']))
           ->setPlaceholder(_('value'))
           ->setWidth(ZBX_TEXTAREA_TINY_WIDTH);
       
       (new CWidgetFormView($data))
           ->addField(
               new CWidgetFieldMultiSelectItemView($data['fields']['itemid'], $data['captions']['items']['itemid'])
           )
           ->addField(
               new CWidgetFieldCheckBoxView($data['fields']['adv_conf'])
           )
           ->addField(
               new CWidgetFieldColorView($data['fields']['chart_color']),
               'js-advanced-configuration'
           )
           ->addField(
               new CWidgetFieldNumericBoxView($data['fields']['value_min']),
               'js-advanced-configuration'
           )
           ->addField(
               new CWidgetFieldNumericBoxView($data['fields']['value_max']),
               'js-advanced-configuration'
           )
           ->addItem([
               $lefty_units->getLabel()->addClass('js-advanced-configuration'),
               (new CFormField([
                   $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
                   $lefty_static_units->getView()
               ]))->addClass('js-advanced-configuration')
           ])
           ->addField(
               new CWidgetFieldTextBoxView($data['fields']['description']),
               'js-advanced-configuration'
           )
           ->includeJsFile('widget.edit.js.php')
           ->addJavaScript('widget_lesson_gauge_chart_form.init('.json_encode([
               'color_palette' => CWidgetFieldGraphDataSet::DEFAULT_COLOR_PALETTE
           ], JSON_THROW_ON_ERROR).');')
           ->show();
  1. Вернитесь на панель, переключитесь в режим редактирования и нажмите на значок шестеренки в виджете, чтобы открыть форму настройки виджета. Форма настройки виджета теперь содержит новый расширяемый/сворачиваемый раздел Расширенная конфигурация.

  1. Отметьте флажок Расширенная конфигурация, чтобы увидеть дополнительные поля конфигурации виджета. Заполните поля значениями и выберите цвет виджета.

  1. Нажмите Применить в форме настройки виджета. Затем нажмите Сохранить изменения в правом верхнем углу, чтобы сохранить панель.

  2. Откройте actions/WidgetView.php и обновите контроллер.

Свойство $this->fields_values теперь содержит значения всех полей Расширенной конфигурации. Завершите настройку контроллера, чтобы обеспечить передачу конфигурации и выбранного значения элемента данных в представление виджета.

ui/modules/lesson_gauge_chart/actions/WidgetView.php

<?php
       
       namespace Modules\LessonGaugeChart\Actions;
       
       use API,
           CControllerDashboardWidgetView,
           CControllerResponseData;
       
       class WidgetView extends CControllerDashboardWidgetView {
       
           protected function doAction(): void {
               $db_items = API::Item()->get([
                   'output' => ['itemid', 'value_type', 'name', 'units'],
                   'itemids' => $this->fields_values['itemid'],
                   'webitems' => true,
                   'filter' => [
                       'value_type' => [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT]
                   ]
               ]);
       
               $history_value = null;
       
               if ($db_items) {
                   $item = $db_items[0];
       
                   $history = API::History()->get([
                       'output' => API_OUTPUT_EXTEND,
                       'itemids' => $item['itemid'],
                       'history' => $item['value_type'],
                       'sortfield' => 'clock',
                       'sortorder' => ZBX_SORT_DOWN,
                       'limit' => 1
                   ]);
       
                   if ($history) {
                       $history_value = convertUnitsRaw([
                           'value' => $history[0]['value'],
                           'units' => $item['units']
                       ]);
                   }
               }
       
               $this->setResponse(new CControllerResponseData([
                   'name' => $this->getInput('name', $this->widget->getName()),
                   'history' => $history_value,
                   'fields_values' => $this->fields_values,
                   'user' => [
                       'debug_mode' => $this->getDebugMode()
                   ]
               ]));
           }
       }
  1. Откройте и измените views/widget.view.php.

Вам нужно создать контейнер для индикаторного графика, который вы нарисуете на следующих этапах, и контейнер для описания.

Чтобы передать значения в JavaScript в виде JSON-объекта, используйте метод setVar().

ui/modules/lesson_gauge_chart/views/widget.view.php

<?php
       
       /**
        * Gauge chart widget view.
        *
        * @var CView $this
        * @var array $data
        */
       
       (new CWidgetView($data))
           ->addItem([
               (new CDiv())->addClass('chart'),
               $data['fields_values']['description']
                   ? (new CDiv($data['fields_values']['description']))->addClass('description')
                   : null
           ])
           ->setVar('history', $data['history'])
           ->setVar('fields_values', $data['fields_values'])
           ->show();
  1. Создайте новую директорию assets в директории lesson_gauge_chart. Эта директория будет использоваться для хранения JavaScript, CSS и, возможно, других ресурсов, таких как шрифты или изображения.

  2. Для JavaScript, используемого в представлении виджета, создайте директорию js в директории assets.

  3. Создайте файл class.widget.js в директории assets/js.

Этот JavaScript-класс виджета будет расширять базовый JavaScript-класс всех виджетов панели - CWidget.

Панель полагается на правильную реализацию виджета и передает любую необходимую информацию виджету, вызывая соответствующие JavaScript-методы. Панель также ожидает, что виджет будет генерировать события при взаимодействии. Таким образом, класс CWidget содержит набор методов с реализацией поведения виджета по умолчанию, которые могут быть настроены путем расширения класса.

В данном случае требуется определенная настройка, поэтому пользовательская логика будет реализована для следующего поведения виджета:

  • инициализация виджета, которая отвечает за определение его начального состояния (см. метод onInitialize())
  • отображение содержимого виджета (то есть построение индикаторного графика), если процесс обновления виджета завершился успешно и без ошибок (см. метод processUpdateResponse(response) и связанные с ним методы _resizeChart() и _resizeChart())
  • изменение размера виджета (см. метод onResize() и связанный с ним метод _resizeChart())

Для других аспектов виджета индикаторного графика будет использоваться реализация поведения виджета по умолчанию. Чтобы узнать больше о JavaScript-методах класса CWidget, см. JavaScript.

Поскольку этот JavaScript необходим для отображения виджета, он должен быть загружен вместе со страницей панели. Чтобы включить загрузку JavaScript, вам потребуется обновить параметры assets/js и js_class в файле manifest.json, как показано на следующем шаге.

ui/modules/lesson_gauge_chart/assets/js/class.widget.js

class WidgetLessonGaugeChart extends CWidget {
       
           static UNIT_AUTO = 0;
           static UNIT_STATIC = 1;
       
           _init() {
               super._init();
       
               this._refresh_frame = null;
               this._chart_container = null;
               this._canvas = null;
               this._chart_color = null;
               this._min = null;
               this._max = null;
               this._value = null;
               this._last_value = null;
               this._units = '';
           }
       
           _processUpdateResponse(response) {
               if (response.history === null) {
                   this._value = null;
                   this._units = '';
               }
               else {
                   this._value = Number(response.history.value);
                   this._units = response.fields_values.value_units == WidgetLessonGaugeChart.UNIT_AUTO
                       ? response.history.units
                       : response.fields_values.value_static_units;
               }
       
               this._chart_color = response.fields_values.chart_color;
               this._min = Number(response.fields_values.value_min);
               this._max = Number(response.fields_values.value_max);
       
               if (this._canvas === null) {
                   super._processUpdateResponse(response);
       
                   this._chart_container = this._content_body.querySelector('.chart');
                   this._canvas = document.createElement('canvas');
       
                   this._chart_container.appendChild(this._canvas);
       
                   this._resizeChart();
               }
               else {
                   this._updatedChart();
               }
           }
       
           resize() {
               super.resize();
       
               if (this._state === WIDGET_STATE_ACTIVE) {
                   this._resizeChart();
               }
           }
       
           _resizeChart() {
               const ctx = this._canvas.getContext('2d');
               const dpr = window.devicePixelRatio;
       
               this._canvas.style.display = 'none';
               const size = Math.min(this._chart_container.offsetWidth, this._chart_container.offsetHeight);
               this._canvas.style.display = '';
       
               this._canvas.width = size * dpr;
               this._canvas.height = size * dpr;
       
               ctx.scale(dpr, dpr);
       
               this._canvas.style.width = `${size}px`;
               this._canvas.style.height = `${size}px`;
       
               this._refresh_frame = null;
       
               this._updatedChart();
           }
       
           _updatedChart() {
               if (this._last_value === null) {
                   this._last_value = this._min;
               }
       
               const start_time = Date.now();
               const end_time = start_time + 400;
       
               const animate = () => {
                   const time = Date.now();
       
                   if (time <= end_time) {
                       const progress = (time - start_time) / (end_time - start_time);
                       const smooth_progress = 0.5 + Math.sin(Math.PI * (progress - 0.5)) / 2;
                       let value = this._value !== null ? this._value : this._min;
                       value = (this._last_value + (value - this._last_value) * smooth_progress - this._min) / (this._max - this._min);
       
                       const ctx = this._canvas.getContext('2d');
                       const size = this._canvas.width;
                       const char_weight = size / 12;
                       const char_shadow = 3;
                       const char_x = size / 2;
                       const char_y = size / 2;
                       const char_radius = (size - char_weight) / 2 - char_shadow;
       
                       const font_ratio = 32 / 100;
       
                       ctx.clearRect(0, 0, size, size);
       
                       ctx.beginPath();
                       ctx.shadowBlur = char_shadow;
                       ctx.shadowColor = '#bbb';
                       ctx.strokeStyle = '#eee';
                       ctx.lineWidth = char_weight;
                       ctx.lineCap = 'round';
                       ctx.arc(char_x, char_y, char_radius, Math.PI * 0.749, Math.PI * 2.251, false);
                       ctx.stroke();
       
                       ctx.beginPath();
                       ctx.strokeStyle = `#${this._chart_color}`;
                       ctx.lineWidth = char_weight - 2;
                       ctx.lineCap = 'round';
                       ctx.arc(char_x, char_y, char_radius, Math.PI * 0.75,
                           Math.PI * (0.75 + (1.5 * Math.min(1, Math.max(0, value)))), false
                           );
                       ctx.stroke();
       
                       ctx.shadowBlur = 2;
                       ctx.fillStyle = '#1f2c33';
                       ctx.font = `${(char_radius * font_ratio)|0}px Arial`;
                       ctx.textAlign = 'center';
                       ctx.textBaseline = 'middle';
                       ctx.fillText(`${this._value !== null ? this._value : t('No data')}${this._units}`,
                           char_x, char_y, size - char_shadow * 4 - char_weight * 2
                       );
       
                       ctx.fillStyle = '#768d99';
                       ctx.font = `${(char_radius * font_ratio * .5)|0}px Arial`;
                       ctx.textBaseline = 'top';
       
                       ctx.textAlign = 'left';
                       ctx.fillText(`${this._min}${this._min != '' ? this._units : ''}`,
                           char_weight * .75, size - char_weight * 1.25, size / 2 - char_weight
                       );
       
                       ctx.textAlign = 'right';
                       ctx.fillText(`${this._max}${this._max != '' ? this._units : ''}`,
                           size - char_weight * .75, size - char_weight * 1.25, size / 2 - char_weight
                       );
       
                       requestAnimationFrame(animate);
                   }
                   else {
                       this._last_value = this._value;
                   }
               };
       
               requestAnimationFrame(animate);
           }
       }
  1. Откройте manifest.json и добавьте:
  • имя файла (class.widget.js) в массив в разделе assets/js;
  • имя класса (WidgetLessonGaugeChart) в параметр js_class в разделе widget.

Класс WidgetLessonGaugeChart теперь будет автоматически загружаться вместе с панелью.

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix SIA",
           "actions": {
               "widget.lesson_gauge_chart.view": {
                   "class": "WidgetView"
               }
           },
           "widget": {
               "js_class": "WidgetLessonGaugeChart"
           },
           "assets": {
               "js": ["class.widget.js"]
           }
       }

Добавление стилей CSS в виджет

В этом разделе вы узнаете, как добавлять собственные стили CSS, чтобы виджет выглядел более привлекательно.

  1. Для стилей виджетов создайте новый каталог css в каталоге assets.

  2. Создайте файл widget.css в каталоге assets/css. Чтобы стилизовать элементы виджета, используйте селектор div.dashboard-widget-{widget id}. Чтобы настроить CSS для всего виджета, используйте селектор form.dashboard-widget-{idget id}

ui/modules/lesson_gauge_chart/assets/css/widget.css

div.dashboard-widget-lesson_gauge_chart {
           display: grid;
           grid-template-rows: 1fr;
           padding: 0;
       }
       
       div.dashboard-widget-lesson_gauge_chart .chart {
           display: grid;
           align-items: center;
           justify-items: center;
       }
       
       div.dashboard-widget-lesson_gauge_chart .chart canvas {
           background: white;
       }
       
       div.dashboard-widget-lesson_gauge_chart .description {
           padding-bottom: 8px;
           font-size: 1.750em;
           line-height: 1.2;
           text-align: center;
       }
       
       .dashboard-grid-widget-hidden-header div.dashboard-widget-lesson_gauge_chart .chart {
           margin-top: 8px;
       }
  1. Откройте manifest.json и добавьте имя файла CSS (widget.css) в массив в разделе assets/css. Это позволит стилям CSS, определенным в widget.css, загружаться вместе со страницей панели.

ui/modules/lesson_gauge_chart/manifest.json

{
           "manifest_version": 2.0,
           "id": "lesson_gauge_chart",
           "type": "widget",
           "name": "Gauge chart",
           "namespace": "LessonGaugeChart",
           "version": "1.0",
           "author": "Zabbix",
           "actions": {
               "widget.lesson_gauge_chart.view": {
                   "class": "WidgetView"
               }
           },
           "widget": {
               "js_class": "WidgetLessonGaugeChart"
           },
           "assets": {
               "css": ["widget.css"],
               "js": ["class.widget.js"]
           }
       }
  1. Обновите страницу панели, чтобы увидеть готовую версию виджета.