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

これは、シンプルなダッシュボードウィジェットを作成する方法を示すステップバイステップのチュートリアルです。 このウィジェットのすべてのファイルを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)は、値を単一の形式に変換してデータベースに保存します。

ウィジェットのフォームファイルは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. ウィジェット設定フォームで適用をクリックします。 次に、右上の変更を保存をクリックしてダッシュボードを保存します。 新しい説明はどこにも表示されず、ウィジェットには引き続き「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']に含まれる説明フィールドの値を使用できるようになりました。 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. ウィジェット設定フォームには新しい入力フィールド アイテム が含まれています。 ホスト「Zabbix server」とアイテム「Load average (1m avg)」を選択します。

  1. ウィジェット設定フォームで 適用 をクリックします。 次に、右上隅の 変更を保存 をクリックしてダッシュボードを保存します。

  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. ウィジェット設定フォームで適用をクリックします。 次に、右上隅の変更を保存をクリックしてダッシュボードを保存します。

  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. ダッシュボードページを更新して、ウィジェットの完成版を確認します。