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

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

作成するもの

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

パート I - "Hello, world!"

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

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

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

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

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

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

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

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

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

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

ウィジェットのビューファイルは、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'] に含まれる)をウィジェットビューで使用できます。
    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. ダッシュボードページを更新します。 ウィジェットに最新のアイテム値が表示されます。

Advanced configurationを構成ビューに追加

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

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

Widgetクラスは、CWidget基本クラスを拡張して、デフォルトのウィジェット設定 (この場合は翻訳) を追加/上書きします。 以下に示すJavaScriptは、データが欠落している場合に文字列"No data"を表示します。 Zabbix UI翻訳ファイルには"No data"という文字列が存在します。

ウィジェット定数がある場合は、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()メソッドは、CSSクラス文字列を2番目のパラメーターとして受け取ります。

  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 を開いて変更します。

次のステップで描画するゲージチャート用のコンテナと、説明用のコンテナを作成する必要があります。

値を JSON オブジェクトとして JavaScript に渡すには、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. ダッシュボードページを更新して、ウィジェットの完成版を確認します。