ウィジェットの作成 (チュートリアル)

これは、シンプルなダッシュボードウィジェットを作成する方法を示すステップバイステップのチュートリアルです。 このウィジェットのすべてのファイルをZIPアーカイブとしてダウンロードできます: lesson_gauge_chart.zip

作成するもの

このチュートリアルでは、まず基本的な「Hello, world!」ウィジェットを作成し、その後、アイテムの値をゲージチャートとして表示するより高度なウィジェットに変換します。 完成したウィジェットは次のようになります。

パート I - "Hello, world!"

このセクションでは、最小限必要なウィジェット要素を作成し、新しいウィジェットをZabbixフロントエンドに追加する方法を学びます。

Zabbix Webインターフェースに空のウィジェットを追加する

  1. Zabbix Webインターフェースのインストール先の modules ディレクトリに、lesson_gauge_chart ディレクトリを作成します(例: zabbix/ui/modules)。

すべてのカスタムウィジェットは外部モジュールとして扱われ、Zabbix Webインターフェースのインストール先の modules ディレクトリに追加する必要があります(例: zabbix/ui/modules)。 ディレクトリ zabbix/ui/widgets は Zabbix 標準ウィジェット用に予約されており、Zabbix UI とともに更新されます。

  1. 基本的なウィジェットメタデータを含む manifest.json ファイルを作成します(対応する parameters の説明を参照してください)。

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 Webインターフェースで、Administration → General → Modules セクションに移動し、Scan directory ボタンをクリックします。

  1. 一覧から新しいモジュール Gauge chart を見つけ、"Disabled" ハイパーリンクをクリックして、モジュールの状態を "Disabled" から "Enabled" に変更します(モジュールが一覧に表示されない場合は、troubleshooting セクションを参照してください)。

  1. ダッシュボードを開き、編集モードに切り替えて新しいウィジェットを追加します。 Type フィールドで "Gauge chart" を選択します。

  1. この時点で、Gauge chart ウィジェットの設定には共通のウィジェット項目である NameRefresh interval のみが含まれています。 Add をクリックして、ウィジェットをダッシュボードに追加します。

  1. ダッシュボードに空のウィジェットが表示されるはずです。 右上の Save changes をクリックして、ダッシュボードを保存します。

ウィジェットビューの追加

ウィジェットのviewファイルはviewsディレクトリ(このチュートリアルではui/modules/lesson_gauge_chart/views/)に配置する必要があります。 ファイル名がデフォルトのwidget.view.phpの場合、manifest.jsonファイルに登録する必要はありません。 ファイル名が異なる場合は、manifest.jsonファイルのactions/widget.lesson_gauge_chart.viewセクションで指定してください。

  1. lesson_gauge_chartディレクトリ内にviewsディレクトリを作成します。

  2. 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, 'Hello, world!')
    )
    ->show();
  1. ダッシュボードをリフレッシュします。 Gauge chartウィジェットに「Hello, world!」が表示されます。

パート II - ゲージチャート

設定ビューに設定を追加し、ウィジェットビューで使用する

このセクションでは、ウィジェットの設定フィールドを追加し、入力された値をウィジェットビューにテキストとして表示する方法を学びます。

ウィジェットの設定は、フォーム (Zabbix\Widgets\CWidgetForm) とウィジェットフォームビュー (widget.edit.php) で構成されます。 フィールド (Zabbix\Widgets\CWidgetField) を追加するには、Zabbix\Widgets\CWidgetForm を拡張する WidgetForm クラスを作成する必要があります。

フォームには、ユーザーが入力した値を検証するために使用される、さまざまな種類のフィールド (Zabbix\Widgets\CWidgetField) が含まれます。 各入力要素タイプに対応するフォームフィールド (Zabbix\Widgets\CWidgetField) は、値をデータベースに保存するための単一の形式に変換します。

ウィジェットの form ファイルは includes ディレクトリに配置する必要があります(このチュートリアルでは ui/modules/lesson_gauge_chart/includes/)。 ファイル名が既定の WidgetForm.php の場合は、manifest.json ファイルに登録する必要はありません。 ファイル名が異なる場合は、manifest.json ファイルの widget/form_class セクションで指定してください。

  1. lesson_gauge_chart ディレクトリに新しい includes ディレクトリを作成します。

  2. includes ディレクトリに WidgetForm.php ファイルを作成します。

ui/modules/lesson_gauge_chart/includes/WidgetForm.php

<?php

namespace Modules\LessonGaugeChart\Includes;

use Zabbix\Widgets\CWidgetForm;

class WidgetForm extends CWidgetForm {
}
  1. ウィジェット設定フォームに Description フィールドを追加します。 これは通常のテキストフィールドで、ユーザーは任意の文字を入力できます。 これには 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

/**
 * Gauge chart widget form view.
 *
 * @var CView $this
 * @var array $data
 */

(new CWidgetFormView($data))
    ->addField(
        new CWidgetFieldTextBoxView($data['fields']['description'])
    )
    ->show();
  1. ダッシュボードに移動し、ウィジェット内の歯車アイコンをクリックしてウィジェット設定フォームを開きます。

  2. ウィジェット設定フォームに新しい Description テキストフィールドが追加されています。 任意の値を入力します。たとえば、Gauge chart description です。

  1. ウィジェット設定フォームで Apply をクリックします。 次に、右上の Save changes をクリックしてダッシュボードを保存します。 新しい説明はどこにも表示されず、ウィジェットには引き続き "Hello, world!" が表示されていることに注意してください。

新しい説明をウィジェットに表示するには、Description フィールドの値をデータベースから取得し、ウィジェットビューに渡す必要があります。 そのために、アクションクラスを作成します。

  1. lesson_gauge_chart ディレクトリに新しい actions ディレクトリを作成します。

  2. actions ディレクトリに WidgetView.php ファイルを作成します。 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 を開き、actions/widget.lesson_gauge_chart.view セクションに WidgetView をアクションクラスとして登録します。

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'] に含まれる description フィールドの値をウィジェットビューで使用できるようになります。 views/widget.view.php を開き、静的テキスト "Hello, world!" を $data['description'] に置き換えます。

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'])
    )
    ->show();
  1. ダッシュボードページを更新します。 これで、"Hello, world!" の代わりにウィジェットの説明テキストが表示されるはずです。

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. ウィジェット設定フォームに新しい入力フィールド Item が追加されています。
    ホスト "Zabbix server" とアイテム "Load average (1m avg)" を選択します。

  1. ウィジェット設定フォームで Apply をクリックします。
    その後、右上の Save changes をクリックしてダッシュボードを保存します。

  2. actions/WidgetView.php を開いて修正します。

これ以降、アイテムIDはウィジェットコントローラー内の $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. ダッシュボードページを更新します。
    ウィジェットに最新のアイテム値が表示されます。

設定ビューに詳細設定を追加する

このセクションでは、色、最小値と最大値、単位、そして前の手順で作成した Description フィールドなどの任意パラメータを含む、展開/折りたたみ可能な Advanced configuration セクションを追加する方法を学びます。

  1. メインのウィジェットディレクトリ lesson_gauge_chartWidget.php ファイルを作成し、新しい Widget クラスを作成します。

Widget クラスは CWidget 基底クラスを拡張し、既定のウィジェット設定(この場合は翻訳)を追加/上書きします。
以下の JavaScript は、データがない場合に文字列 "No data" を表示します。
"No data" 文字列は 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\{
    CWidgetFieldColor,
    CWidgetFieldMultiSelectItem,
    CWidgetFieldNumericBox,
    CWidgetFieldSelect,
    CWidgetFieldTextBox
};

/**
 * Gauge chart widget form.
 */
class WidgetForm extends CWidgetForm {

    public const DEFAULT_COLOR_PALETTE = [
        'FF465C', 'B0AF07', '0EC9AC', '524BBC', 'ED1248', 'D1E754', '2AB5FF', '385CC7', 'EC1594', 'BAE37D',
        '6AC8FF', 'EE2B29', '3CA20D', '6F4BBC', '00A1FF', 'F3601B', '1CAE59', '45CFDB', '894BBC', '6D6D6D'
    ];

    public function addFields(): self {
        return $this
            ->addField(
                (new CWidgetFieldMultiSelectItem('itemid', _('Item')))
                    ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK)
                    ->setMultiple(false)
            )
            ->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 を開き、設定ビューにフィールドの視覚コンポーネントを追加します。

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

<?php

/**
 * Gauge chart widget form view.
 *
 * @var CView $this
 * @var array $data
 */

$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']))
            ->setPopupParameter('numeric', true)
    )
    ->addFieldset(
        (new CWidgetFormFieldsetCollapsibleView(_('Advanced configuration')))
            ->addField(
                new CWidgetFieldColorView($data['fields']['chart_color'])
            )
            ->addField(
                new CWidgetFieldNumericBoxView($data['fields']['value_min'])
            )
            ->addField(
                new CWidgetFieldNumericBoxView($data['fields']['value_max'])
            )
            ->addItem([
                $lefty_units->getLabel(),
                (new CFormField([
                    $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
                    $lefty_static_units->getView()
                ]))
            ])
            ->addField(
                new CWidgetFieldTextBoxView($data['fields']['description'])
            )
    )
    ->show();

CWidgetFormView クラスの addField() メソッドは、第2引数として CSS クラス文字列を受け取ります。

  1. ダッシュボードに戻り、編集モードに切り替えて、ウィジェット内の歯車アイコンをクリックし、ウィジェット設定フォームを開きます。
    ウィジェット設定フォームには、新しい展開/折りたたみ可能なセクション Advanced configuration が追加されています。

  1. Advanced configuration セクションを展開すると、追加のウィジェット設定フィールドが表示されます。
    フィールド Color にはまだカラーピッカーがありません。
    これは、カラーピッカーを JavaScript で初期化する必要があるためです。これは次のセクション - ウィジェットに JavaScript を追加する - で追加します。

ウィジェットに JavaScript を追加する

このセクションでは、JavaScript で作成したゲージチャートを追加し、最新値が正常か、または高すぎる/低すぎるかを表示する方法を学びます。

  1. views ディレクトリに widget.edit.js.php ファイルを作成します。

JavaScript は、設定画面でカラーピッカーを初期化する役割を担います。

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._unit_select = document.getElementById('value_units');
        this._unit_value = document.getElementById('value_static_units');

        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() {
        this._unit_value.disabled = this._unit_select.value == <?= Widget::UNIT_AUTO ?>;
    }
};
  1. views/widget.edit.php を開き、JavaScript を含む widget.edit.js.php ファイルを設定画面に追加します。
    これには 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 Modules\LessonGaugeChart\Includes\WidgetForm;

$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']))
            ->setPopupParameter('numeric', true)
    )
    ->addFieldset(
        (new CWidgetFormFieldsetCollapsibleView(_('Advanced configuration')))
            ->addField(
                new CWidgetFieldColorView($data['fields']['chart_color'])
            )
            ->addField(
                new CWidgetFieldNumericBoxView($data['fields']['value_min'])
            )
            ->addField(
                new CWidgetFieldNumericBoxView($data['fields']['value_max'])
            )
            ->addItem([
                $lefty_units->getLabel(),
                (new CFormField([
                    $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
                    $lefty_static_units->getView()
                ]))
            ])
            ->addField(
                new CWidgetFieldTextBoxView($data['fields']['description'])
            )
    )
    ->includeJsFile('widget.edit.js.php')
    ->addJavaScript('widget_lesson_gauge_chart_form.init('.json_encode([
        'color_palette' => WidgetForm::DEFAULT_COLOR_PALETTE
    ], JSON_THROW_ON_ERROR).');')
    ->show();
  1. ダッシュボードに戻り、ウィジェット内の歯車アイコンをクリックしてウィジェット設定フォームを開きます。
    次に、Advanced configuration セクションを展開して、初期化されたカラーピッカーを表示します。
    各フィールドに値を入力し、ゲージチャートの色を選択します。

  1. ウィジェット設定フォームで Apply をクリックします。
    その後、右上の Save changes をクリックしてダッシュボードを保存します。

  2. actions/WidgetView.php を開き、コントローラーを更新します。

$this->fields_values プロパティには、すべての Advanced configuration フィールドの値が含まれるようになっています。
設定と選択されたアイテム値をウィジェットビューに渡せるよう、コントローラーを完成させます。

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. lesson_gauge_chart ディレクトリ内に新しい assets ディレクトリを作成します。
    このディレクトリは、JavaScript、CSS、必要に応じてフォントや画像などの他のアセットを保存するために使用します。

  2. ウィジェットビュー用の JavaScript として、assets ディレクトリ内に js ディレクトリを作成します。

  3. assets/js ディレクトリに class.widget.js ファイルを作成します。

この JavaScript ウィジェットクラスは、すべてのダッシュボードウィジェットの基底 JavaScript クラスである CWidget を継承します。

ダッシュボードはウィジェットの正しい実装に依存しており、関連する情報をそれぞれの JavaScript メソッドを呼び出すことでウィジェットに伝えます。
また、ダッシュボードは、何らかの操作が発生したときにウィジェットがイベントを生成することも期待しています。
そのため、CWidget クラスには、ウィジェットの動作のデフォルト実装を持つ一連のメソッドが含まれており、クラスを継承することでカスタマイズできます。

このケースでは一部のカスタマイズが必要なため、次のウィジェット動作について独自ロジックを実装します。

  • ウィジェットの初期化。ウィジェットの初期状態を定義する役割があります(onInitialize() メソッドを参照)。
  • ウィジェットの更新処理が成功し、エラーがない場合にウィジェット内容を表示すること、つまりゲージチャートを描画すること(processUpdateResponse(response) メソッド、および関連する _resizeChart()_updatedChart() メソッドを参照)。
  • ウィジェットのサイズ変更(onResize() メソッド、および関連する _resizeChart() メソッドを参照)。

ゲージチャートウィジェットのその他の側面については、ウィジェット動作のデフォルト実装を使用します。
CWidget クラスの JavaScript メソッドの詳細については、JavaScript を参照してください。

この JavaScript はウィジェットビューに必要なため、ダッシュボードページとともに読み込まれる必要があります。
JavaScript の読み込みを有効にするには、手順 10 に示すように manifest.json ファイルの assets/js および js_class パラメーターを更新する必要があります。

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

class WidgetLessonGaugeChart extends CWidget {

    static UNIT_AUTO = 0;
    static UNIT_STATIC = 1;

    onInitialize() {
        super.onInitialize();

        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);

        super.processUpdateResponse(response);
    }

    setContents(response) {
        if (this._canvas === null) {
            super.setContents(response);

            this._chart_container = this._body.querySelector('.chart');
            this._chart_container.style.height =
                `${this._getContentsSize().height - this._body.querySelector('.description').clientHeight}px`;
            this._canvas = document.createElement('canvas');

            this._chart_container.appendChild(this._canvas);

            this._resizeChart();
        }

        this._updatedChart();
    }

    onResize() {
        super.onResize();

        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 を開き、次を追加します。
  • assets/js セクションの配列にファイル名 (class.widget.js) を追加する。
  • widget セクションの js_class パラメーターにクラス名 (WidgetLessonGaugeChart) を追加する。

これで 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",
    "actions": {
        "widget.lesson_gauge_chart.view": {
            "class": "WidgetView"
        }
    },
    "widget": {
        "js_class": "WidgetLessonGaugeChart"
    },
    "assets": {
        "js": ["class.widget.js"]
    }
}

CSSスタイルをウィジェットに追加

このセクションでは、カスタムCSSスタイルを追加してウィジェットをより魅力的に見せる方法を学びます。

  1. ウィジェットスタイルの場合は、assetsディレクトリに新しいディレクトリcssを作成します。

  2. assets/cssディレクトリにwidget.cssファイルを作成します。 ウィジェット要素のスタイルを設定するには、セレクターdiv.dashboard-widget-{widget id}を使用します。 ウィジェット全体のCSSを設定するには、セレクターform.dashboard-widget-{widget 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セクションの配列に追加します。 これにより、widget.cssで定義された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. ダッシュボードページを更新して、ウィジェットの完成版を確認します。