デモで学ぶ業務アプリのUI開発(4) – サービス監視ダッシュボード

メシウスのWebサイトではJavaScriptライブラリを活用した業務アプリのUIの実装サンプルを、ダウンロード可能なソースコード付きで多数公開しています。

本連載ではWebサイトで公開しているサンプルアプリケーションを例に、さまざまな業務アプリケーションのUIの実装のポイントや、コントロールの選定ポイントを解説していきます。第4回となる本記事はJavaScript UIライブラリ「Wijmo(ウィジモ)」の各種コントロールを使用した「サービス監視ダッシュボード」デモの解説です。

サービス監視ダッシュボード

利用しているコントロール

サービス監視ダッシュボードデモではWijmoの以下のコントロールを使用しています。

コントロール名利用目的イメージ
ComboBox表示するデータ期間の選択。コンボボックス
RadialGauge監視データの最新値を表示。円形ゲージ
TooltipRadialGauge上に各範囲の説明を表示。ツールチップ
FlexChart監視データの時系列表示。折れ線チャート
サービス費用の表示。横棒チャート
FlexPieAPI使用率の表示。円グラフ

主要ソースファイル

本デモはJavaScriptフレームワーク「Vue.js」を利用して実装されており、主なソースファイルは以下のようになっています。

フォルダファイル名内容
srcApp.vueルートコンポーネント。
ComboBoxの処理の実装。
その他のコンポーネントの読み込み。
src/componentsCpuUsage.vue
MemoryUsage.vue
InsessionLatency.vue
DiskUsage.vue
RootVolumeDiskUsage.vue
RadialGaugeを使用した監視データの表示。
ConecctionInformationChart.vue
InsessionLatencyChart.vue
UdpPacketLossRateChart.vue
CpuUsageChart.vue
MemoryUsageChart.vue
VolumeInfomationChart.vue
FlexChartを使用した監視データの時系列表示。
ダミーデータの生成。
ServiceCost.vueFlexChartを使用したサービス費用の表示。
ApiUsage.vueFlexPieを使用したAPI使用率の表示。
src/utilsguage.tsRadialGaugeを使用したコンポーネントの共通処理。
chart.tsFlexChartを使用したコンポーネントの共通処理。

各コントロールの解説

ここからは各コントロールのソースコードを抜粋し、ポイントとなる部分を解説します。

RadialGauge

Gauge(ゲージ)は、単一の値が範囲や目標値と比較して、どのレベルにあるかを直観的に把握できるUIです。本デモでは、CPU使用率など5項目の最新値を円形ゲージで表示しています。

円形ゲージ

本デモでは、ゲージ領域を「正常(緑)」、「注意(オレンジ)」、「危険(赤)」の3つの範囲に分けることで、異常の有無を一目で判断しやすくしています。

<template>
  <div class="cpu-usage">
    <div class="card__title">CPU使用率</div>

    <wj-radial-gauge
      class="gauge"
      :initialized="onGaugeInit"
      :thickness="0.2"
      :start-angle="-20"
      :sweep-angle="220"
      :min="0"
      :max="1"
      :value="lastCpuUsage / 100"
      :is-read-only="true"
      format="p2"
    >
      <!-- ポインター(現在の値) -->
      <wj-range wj-property="pointer" :thickness="0.2" color="black"></wj-range>
      <!-- ゲージ領域を3色に分割 -->
      <wj-range name="low" :min="0.0" :max="0.8" :color="greenStyle.stroke"></wj-range>
      <wj-range name="high" :min="0.8" :max="0.9" :color="orangeStyle.stroke"></wj-range>
      <wj-range name="top" :min="0.9" :max="1.0" :color="redStyle.stroke"></wj-range>
    </wj-radial-gauge>
  </div>
</template>
・・・

テキストのカスタマイズ

RadialGaugeのgetTextプロパティを利用してゲージ中央に表示する文字列をカスタマイズすることができます。「セッション中遅延」のゲージでは、以下のコードのようにformatプロパティに"n1"を設定して小数点以下1桁での表示を行い、その値に対してgetTextプロパティで「ms(ミリ秒)」の文字列を追加しています。

・・・
    <wj-radial-gauge
      class="gauge"
      ・・・
      format="n1"
      :get-text="(g: Gauge, part: string, v: number, t: string) => `${t}ms`"
    >
・・・

Tooltip

Tooltip(ツールチップ)は、要素上に追加で情報を表示したい場合に使用するUIです。
今回は、ゲージにマウスオーバーしたときに3つの領域(正常/注意/危険)の範囲を一覧で表示しています。

Tooltipの設定はRadialGaugeのinitializedイベントに追加したハンドラー(onGaugeInit)内で行っています。Tooltipを生成した後、setTooltipメソッドを使ってゲージのホスト要素に対してツールチップを設定しています。また、以下のように表示のカスタマイズも行っています。

  • Tooltipの生成時にshowDelayプロパティとhideDelayプロパティを0にすることで、マウスオーバー時に即座に表示されるように設定。
  • setTooltipメソッドの第2引数でツールチップの表示位置をPopupPosition.Below(要素の下)に設定。
・・・
  <wj-radial-gauge
    class="gauge"
    :initialized="onGaugeInit"
    ・・・
  >
・・・
・・・
export const onGaugeInit = (ctrl: RadialGauge) => {
  const tt = new Tooltip({ showDelay: 0, hideDelay: 0 })
  const el = ctrl.hostElement
  tt.setTooltip(
    el,
    `<div>正常: ${getRangeText(ctrl, 0)}</div><div>注意: ${getRangeText(ctrl, 1)}</div><div>危険: ${getRangeText(ctrl, 2)}</div>`,
    PopupPosition.Below,
  )
}
・・・

ツールチップ内に表示する文字列はHTMLとして定義しており、各範囲の値の部分をgetRangeTextメソッドで動的に生成しています。getRangeTextでは、RadialGaugeのrangesプロパティに設定された最小値・最大値を取得し、範囲の色に合わせたスタイルを設定しています。また、getTextが設定されている場合はそれを優先して使うことで、ゲージ側でカスタマイズされた表示形式をToolTipにもそのまま反映させています。

・・・
const getRangeText = (ctrl: RadialGauge, i: number) => {
  const range = ctrl.ranges[i]

  // getText があれば必ずそれを使う
  const minText = ctrl.getText
    ? ctrl.getText(ctrl, '', range.min, Globalize.format(range.min, ctrl.format))
    : Globalize.format(range.min, ctrl.format)

  const maxText = ctrl.getText
    ? ctrl.getText(ctrl, '', range.max, Globalize.format(range.max, ctrl.format))
    : Globalize.format(range.max, ctrl.format)

  return `<span style="color:${range.color};">${minText} ~ ${maxText}</span>`
}
・・・

FlexChart

本デモでは、以下の2種類の表示でFlexChart(フレックスチャート)を使用しています。

  • 監視データの時系列表示(折れ線・範囲面チャート)
  • サービス費用の表示(積み上げ横棒チャート)

今回は、監視データの時系列表示を取り上げて解説します。

「セッション中遅延」、「UDPパケット損失率」、「CPU使用率」、「メモリ使用率」のチャートでは、監視データを時系列表示するのに加えて、正常値の範囲を示す「異常検出バンド」を表示しています。また、監視データの中で異常検出バンドを超過している部分を赤色にすることで、異常値であること視覚的にわかりやすくしています。

折れ線・面範囲チャート

系列の設定

FlexChartには複数の種類のチャートを混在して表示することができます。ここでは、FlexChartのchartTypeプロパティをChartType.Lineに設定することでデフォルトでは折れ線チャートとしています。加えて、「異常検出バンド」のSeries設定(以下コードの①部分)でchartTypeプロパティをChartType.Areaにするとともに、bindingプロパティに下限・上限を表すメンバー名(bandLo・bandHi)を指定することで、この系列のみ帯状のエリア(範囲面チャート)として表示しています。

また、「異常検出バンド」外にある異常値を別系列として定義し、線色を赤にすることで異常値であること視覚的に分かりやすくしています(以下コードの②部分)。

<template>
  <div class="insession-latency-chart">
    <div class="card__title">セッション中遅延</div>

    <div class="card__chart">
      <wj-flex-chart
        :items-source="data"
        binding-x="t"
        :chart-type="ChartType.Line"
        :tooltip-content="tooltipContent"
      >
        <wj-flex-chart-legend :position="Position.Bottom" />

        <wj-flex-chart-axis
          wj-property="axisX"
          :major-unit="term !== TermType.Day ? 1 : 1 / 24"
          :major-grid="false"
          :format="term !== TermType.Day ? DATE_FORMAT : TIME_FORMAT"
        />

        <wj-flex-chart-axis
          wj-property="axisY"
          title="ミリ秒(ms)"
          :min="min"
          :max="max"
          :major-unit="5"
          :major-grid="true"
          format="n1"
        />
        <!-- ①異常検出バンド(レンジエリア)-->
        <wj-flex-chart-series
          name="異常検出バンド"
          binding="bandLo,bandHi"
          :chart-type="ChartType.Area"
          :style="bandStyle"
        />
        <!-- 実測(折れ線) -->
        <wj-flex-chart-series name="セッション中遅延(正常)" binding="in" :style="greenStyle" />
        <!-- ②バンド外:赤 -->
        <wj-flex-chart-series name="セッション中遅延(異常)" binding="out" :style="redStyle" />
      </wj-flex-chart>
    </div>
  </div>
</template>
・・・

ツールチップのカスタマイズ

前述のRadialGaugeでは独自実装でツールチップを表示していましたが、FlexChartでは標準機能としてツールチップ表示が提供されており、データ系列にマウスオーバーするとツールチップが表示されます。

本デモでは、FlexChartのtooltipプロパティのcontentに関数(tooltipContent)を設定することで、ツールチップの表示内容をカスタマイズしています。
この関数の引数には、チャート上のマウス位置にある要素の情報を持つHitTestInfoインスタンスが渡されるため、そこからデータ系列の情報を取得し、文字色や表示内容のカスタマイズを行っています。

・・・
      <wj-flex-chart
        :items-source="data"
        binding-x="t"
        :chart-type="ChartType.Line"
        :tooltip-content="tooltipContent"
      >
・・・
・・・
/**
 * ツールチップをカスタム表示するロジック。異常検出バンドは上限と下限を表示する
 */
export const tooltipContent = (ht: HitTestInfo): string => {
  if (!ht.series) return ''

  const series = ht.series
  const color = series.style.fill
  const title = series.chart.axisY.title
  const t = ht.item?.t as Date
  const item = ht.item
  return `
    <div>
      <div style="font-weight:600;">${series.name}</div>
      <div>${t.toLocaleString()}</div>
      <div>
        <span style="color:${color}; font-weight:600;">
          ${
            series.binding !== 'bandLo,bandHi'
              ? Globalize.format(item[series.binding], series.chart.axisY.format)
              : Globalize.format(item.bandLo, series.chart.axisY.format) +
                '~' +
                Globalize.format(item.bandHi, series.chart.axisY.format)
          } ${title}
        </span>
      </div>
    </div>
  `
}
・・・

ComboBox

ダッシュボードで表示するデータの期間を切り替えるためにComboBox(コンボボックス)を使用しています。

ComboBoxの選択が変更された際に発生するselectedIndexChangedイベントにハンドラーを追加し、値を変数selectedTermに反映しています。
また、selectedTermはチャートコンポーネント(以下のコードではcpu-usage-chart)にバインドされており、値が変更されると表示データも即座に切り替わります。
さらに、チャートコンポーネント内のデータを切り替える処理の中で、各監視データの最新値(以下のコードではlastCpuUsage)も更新され、ルートコンポーネントを通じてゲージコンポーネント(以下のコードではcpu-usage)に反映されます。

<template>
  ・・・(中略)
    <!-- コンボボックス -->
    <wj-combo-box
      class="term-combobox"
      :initialized="onComboBoxInitialized"
      :itemsSource="TermTypeHeaders"
      displayMemberPath="header"
      selectedValuePath="binding"
    ></wj-combo-box>
      ・・・
      <!-- CPU使用率(ゲージ):lastCpuUsage をバインド-->
      <cpu-usage class="dashboard-gauge-card" :last-cpu-usage="lastCpuUsage" />
      ・・・
      <!-- CPU使用率(チャート):selectedTerm、lastCpuUsage をバインド -->
      <cpu-usage-chart
        class="dashboard-chart-card"
        v-model="lastCpuUsage"
        :term="selectedTerm" 
      ></cpu-usage-chart>
      ・・・
<script setup lang="ts">
・・・
const selectedTerm = ref<TermType>(TermType.Week) // データ期間
const lastCpuUsage = ref(0) // 最新値
・・・
const onComboBoxInitialized = (comboBoxRef: ComboBox) => {
  comboBoxRef.selectedValue = selectedTerm.value
  // 変更監視
  comboBoxRef.selectedIndexChanged.addHandler(() => {
    selectedTerm.value = comboBoxRef.selectedValue
  })
}
・・・
・・・
type Emits = {
  (e: 'update:modelValue', lastCpuUsage: number): void
}
const emit = defineEmits<Emits>()

const props = defineProps<{
  term: string
}>()
・・・

// チャートコンポーネント内での表示データの切り替え
const data = computed(() => {
  const item = allData.value.filter((v) => {
    switch (props.term) {
      case TermType.Day:
        return v.t >= startOfDay(now) && v.t <= now
      case TermType.Week:
        return v.t >= startOfDay(subDays(now, 7)) && v.t <= endOfDay(subDays(now, 1))
      case TermType.PreMonth:
        return v.t >= startOfDay(startOfMonth(subMonths(now, 1))) && v.t <= endOfMonth(subMonths(now, 1))
      case TermType.CurMonth:     
        return v.t >= startOfMonth(startOfDay(now)) && v.t <= endOfDay(subDays(now, 1))
    }
  })
  
  // 最新値を送信
  emit('update:modelValue', item.at(-1)?.value ?? 0)
  return item
})

さいごに

今回はWijmoの各種コントロールを使用した「サービス監視ダッシュボード」デモの実装ポイントを解説しました。

製品サイトでは今回ご紹介したデモアプリケーションをブラウザ上で手軽にお試し可能で、加えてソースコード付きでダウンロードも可能なので、是非こちらもチェックしてみてください。

そのほか、製品サイトでは、Wijmoのトライアル版も公開しておりますので、こちらもご確認ください。

また、ご導入前の製品に関するご相談、ご導入後の各種サービスに関するご質問など、お気軽にお問合せください。

\  この記事をシェアする  /