40以上のコントロールを備えるJavaScript UIライブラリ「Wijmo(ウィジモ)」には、表形式でデータ表示ができるデータグリッドコントロール「FlexGrid(フレックスグリッド)」や、様々なグラフの作成に対応したチャートコントロール「FlexChart(フレックスチャート)」、データの可視化に最適な「Gauge(ゲージ)」など、業務アプリケーション開発に必要なコントロールが豊富に搭載されています。
本記事ではWijmoの各種コントロールを使用して、ReactとBootstrapで売上データを可視化するダッシュボード画面を作成する方法をご紹介します。

目次
開発環境
- React 19.1.1
- Bootstrap 3.4.1
- Wijmo 5.20251.40
Reactプロジェクトの作成
以下のコマンドを実行して、ViteでベースとなるReactアプリケーションを作成します。今回は「react-swc」のオプションを指定し、「SWC(Speedy Web Compiler)」を使用したReactのアプリケーションをスキャフォールドします。
※ 使用可能なテンプレートはこちらをご覧ください。
※ Windows環境でPowerShellを使用する場合、--
は演算子として使用されているので、コマンドプロンプトを使用するか、npm create vite@latest wijmo-react-quickstart --- --template react-swc
として実行してください。
npm create vite@latest wijmo-react-dashboard -- --template react-swc
プロジェクトが作成されたら、以下のコマンドでプロジェクトの配下に移動し、必要なライブラリをインストールします。
cd wijmo-react-dashboard
npm install
以下のコマンドを実行してアプリケーションを起動し、「http://localhost:5173/」にアクセスすると、ベースとなるReactのアプリケーションが確認できます。

Bootstrapのインストールと組み込み
ダッシュボードを作成するにあたり、グリッドシステムとカードのUI、ならびにレスポンシブデザインを実現するためにBootstrapを使用します。さらに同ライブラリが提供するユーティリティクラスを各種スタイルの調整に使用します。「index.html」を以下のように追記し、Bootstrapの参照を追加します。
<!doctype html>
<html lang="ja">
・・・(中略)・・・
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous" />
<title>Wijmoダッシュボード</title>
</head>
・・・(中略)・・・
Wijmoのインストール
次にWijmoのReact用パッケージをアプリケーションにインストールします。
npm install @mescius/wijmo.react.all
テストデータの定義
npmパッケージをインストールしたら、「src」フォルダの配下に「data」フォルダを作成し、「data.js」を追加してダッシュボードに表示するテストデータを定義します。
export const salesByStore = [
{ store: '東京本店', sales: 127250 },
{ store: '関西支店', sales: 107340 },
{ store: '中部支店', sales: 45360 },
{ store: '九州支店', sales: 66250 },
];
export const salesByProducts = [
{ name: '食品', sales: 5500 },
{ name: '家電', sales: 7250 },
{ name: '雑貨', sales: 8500 },
{ name: 'その他', sales: 10750 },
];
export const recentSales = [
{
client: '大和コーヒー',
description: '高級コーヒー豆、国産はちみつ、特選ジャム',
value: 6250,
itemCount: 50,
},
{
client: '日の出燃料',
description: '高火力カセットコンロ、非常用カセットボンベ、携帯カイロ',
value: 2265,
itemCount: 20,
},
{
client: '富士文具製紙',
description: '再生トイレットペーパー、ティッシュペーパー、キッチンペーパー',
value: 4700,
itemCount: 10,
},
{
client: '銀河キッチン',
description: 'アルミホイル、食品用ラップ、冷凍保存袋',
value: 21750,
itemCount: 250,
},
{
client: 'レストラン大京',
description: 'ステーキナイフセット、ブランド箸、カトラリー、包丁研ぎ器',
value: 5000,
itemCount: 5,
},
{
client: '黒川ストア',
description:
'スマートフォン用ガラスフィルム、急速充電器、モバイルバッテリー',
value: 35000,
itemCount: 25,
},
{
client: '武田クリーン',
description: 'ロボット掃除機、コードレス掃除機',
value: 25000,
itemCount: 10,
},
{
client: '中富サービス',
description: '防災セット、防災食、携帯ラジオ',
value: 15000,
itemCount: 50,
},
{
client: '宙スタジオ',
description: '小型高性能ドローン、ドローン用交換バッテリー、プロペラ',
value: 25250,
itemCount: 50,
},
{
client: 'ニホンカメラ',
description: '音波電動歯ブラシ、電動シェーバー',
value: 33200,
itemCount: 40,
},
];
Wijmoの組み込みとダッシュボードの実装
次に「src/App.jsx」を以下のように修正し、Wijmoの組み込みを行なっていきます。
WijmoのReactモジュールをはじめとした必要なモジュールやCSS、日本語カルチャファイル、先ほどのテストデータ等をインポートし、ダッシュボードに表示するゲージやチャート、データグリッドの定義を行います。
※ ライセンスキーを設定しない場合トライアル版を示すメッセージが表示されます。ライセンスキーの入手や設定方法についてはこちらをご覧ください。
// React本体とクラスコンポーネント用Componentをインポート
import React, { Component } from 'react';
// アプリ全体のスタイルをインポート
import './App.css';
// Wijmoのスタイルと必要なコンポーネントをインポート
import '@mescius/wijmo.styles/wijmo.css';
import * as Wijmo from "@mescius/wijmo";
import { FlexGrid, FlexGridColumn } from '@mescius/wijmo.react.grid';
import { FlexChart, FlexPie, FlexChartSeries } from '@mescius/wijmo.react.chart';
import { RadialGauge } from '@mescius/wijmo.react.gauge';
import '@mescius/wijmo.cultures/wijmo.culture.ja';
import { recentSales, salesByStore, salesByProducts } from './data/data';
//Wijmo.setLicenseKey('ここにWijmoのライセンスキーを設定します');
// 売上チャートやゲージなどのパネル表示用コンポーネント
const ChartPanel = ({ title, children }) => {
return (
<div className="col-lg-4 col-md-6 col-sm-12 mt-1">
<div className="card dashboardPanel h-60">
<div className="card-body">
<h5 className="card-title">{title}</h5>
{children}
</div>
</div>
</div>
);
};
// 取引リストなどデータ表示用パネルコンポーネント
const DataPanel = ({ title, children }) => {
return (
<div className="col-sm-12">
<div className="card dashboardRow">
<div className="card-body">
<h5 className="card-title">{title}</h5>
{children}
</div>
</div>
</div>
);
};
// 本日の売上をゲージで表示するコンポーネント
const Gauge = ({ data }) => {
return (
<ChartPanel title="本日の売上">
<div className="gauge">
<RadialGauge
min={0}
max={500000}
step={50}
isReadOnly={true}
thickness={0.15}
format="n0"
value={data}
/>
</div>
</ChartPanel>
);
};
// 支店別売上を棒グラフで表示するコンポーネント
const SalesChart = ({ salesData }) => {
return (
<ChartPanel title="支店別売上">
<FlexChart
itemsSource={salesData}
bindingX="country"
style={{ height: '290px' }}
palette={['rgba(171, 125, 246, 1)']}
>
<FlexChartSeries name="売上" binding="sales" />
</FlexChart>
</ChartPanel>
);
};
// カテゴリ別売上を円グラフで表示するコンポーネント
const SalesPie = ({ salesData }) => {
return (
<ChartPanel title="カテゴリ別売上">
<FlexPie
itemsSource={salesData}
binding="sales"
bindingName="name"
innerRadius={0.7}
style={{ height: '290px' }}
palette={[
'rgba(171, 125, 246, 1)',
'rgba(38, 193, 201, 1)',
'rgba(129, 201, 38, 1)',
'rgba(250, 202, 0, 1)',
]}
/>
</ChartPanel>
);
};
// 本日の取引一覧をグリッドで表示するコンポーネント
const TransactionList = ({ transactions }) => {
return (
<DataPanel title="本日の取引">
<FlexGrid
style={{ width: '100%' }}
itemsSource={transactions}
selectionMode="Row"
alternatingRowStep={1}
>
<FlexGridColumn header="クライアント名" binding="client" width="2*" />
<FlexGridColumn header="説明" binding="description" width="3*" />
<FlexGridColumn header="合計" binding="value" width="1*" />
<FlexGridColumn header="数量" binding="itemCount" width="1*" />
</FlexGrid>
</DataPanel>
);
};
// ダッシュボード全体のメインコンポーネント
class App extends Component {
constructor() {
super();
// 売上・取引データをstateで管理
this.state = {
recentSales: recentSales,
salesByStore: salesByStore,
salesByProducts: salesByProducts,
};
}
// 本日の売上合計を計算
calculateSales() {
let totalSales = 0;
this.state.recentSales.forEach((sale) => (totalSales += sale.value));
return totalSales;
}
// ダッシュボード画面の描画
render() {
return (
<div className="container">
<div className="row">
<Gauge data={this.calculateSales()} />
<SalesChart salesData={this.state.salesByStore} />
<SalesPie salesData={this.state.salesByProducts} />
</div>
<div className="row">
<TransactionList transactions={this.state.recentSales} />
</div>
</div>
);
}
}
// Appコンポーネントをエクスポート
export default App;
以下で上記のコードの実装のポイントを解説していきます。
各種表示用のパネルの定義
以下のコードはWrapperとしてBootstrap関連の定型コードの大部分をひとつの場所にまとめたものです。ダッシュボードをカスタマイズしてパネルを追加する際にこれらのWrapperを使うことで、Wijmoコントロールを含むダッシュボードパネルを簡単に拡張できます。
・・・(中略)・・・
// 売上チャートやゲージなどのパネル表示用コンポーネント
const ChartPanel = ({ title, children }) => {
return (
<div className="col-lg-4 col-md-6 col-sm-12 mt-1">
<div className="card dashboardPanel h-60">
<div className="card-body">
<h5 className="card-title">{title}</h5>
{children}
</div>
</div>
</div>
);
};
// 取引リストなどデータ表示用パネルコンポーネント
const DataPanel = ({ title, children }) => {
return (
<div className="col-sm-12">
<div className="card dashboardRow">
<div className="card-body">
<h5 className="card-title">{title}</h5>
{children}
</div>
</div>
</div>
);
};
・・・(中略)・・・
ゲージ(Gauge)の定義
以下のコードでは本日の会社の売上高を示す円形ゲージ(RadialGauge)のパネルを作成します。先程定義したChartPanel
でWijmoの円形ゲージをラップします。ダッシュボードに合わせて、いくつかのプロパティを渡してカスタマイズします。また、オプションとしてゲージの最小値(min
)と最大値(max
)、読み取り専用かどうか(isReadOnly
)、ゲージの太さ(thickness
)などを設定しています。このゲージコンポーネントにはdata
というパラメータが1つあり、それをRadialGauge
のvalue
プロパティに渡します。
・・・(中略)・・・
// 本日の売上をゲージで表示するコンポーネント
const Gauge = ({ data }) => {
return (
<ChartPanel title="本日の売上">
<div className="gauge">
<RadialGauge
min={0}
max={500000}
step={50}
isReadOnly={true}
thickness={0.15}
format="n0"
value={data}
/>
</div>
</ChartPanel>
);
};
・・・(中略)・・・

棒グラフ(FlexChart)の定義
以下の部分ではゲージを作成したときと同じように、FlexChartをChartPanel
でラップし、いくつかのプロパティを設定しています。
style
にはCSSプロパティが格納されたオブジェクトを設定し、今回はチャートの高さのみを設定してパネル内にすっきり収まるようにします。itemsSource
は、グラフの作成に使用されるデータ項目のリストを設定します。このプロパティには、JavaScriptの配列を渡す必要があります。配列内のオブジェクトには、x軸のラベルとなる文字列プロパティと、y軸の値を含む数値プロパティが1つずつ必要です。この値を使って、FlexChartは選択されたグラフの種類(棒、点、線など)に応じてグラフを描画します。
また、bindingX
をstore
に設定し、FlexChartが提供されたitemsSource
を処理してグラフを構築する際に、各オブジェクトのstore
プロパティをそのデータポイントのx軸ラベルとして使用するよう定義します。
・・・(中略)・・・
// 支店別売上を棒グラフで表示するコンポーネント
const SalesChart = ({ salesData }) => {
return (
<ChartPanel title="支店別売上">
<FlexChart
itemsSource={salesData}
bindingX="store"
style={{ height: '290px' }}
palette={['rgba(171, 125, 246, 1)']}
>
<FlexChartSeries name="売上" binding="sales" />
</FlexChart>
</ChartPanel>
);
};
・・・(中略)・・・

ドーナツグラフ(FlexPie)の定義
以下の部分ではFlexPieを使用して、同様にドーナツチャートのコンポーネントを定義しています。FlexPieはFlexChartと同様のプロパティのセットを持ちますがFlexPieは単一のデータ系列の表示のみが可能です。innerRadius
に0から1の間の値を設定すると、円グラフの中央がくり抜かれてドーナツチャートに変わります。
・・・(中略)・・・
// カテゴリ別売上を円グラフで表示するコンポーネント
const SalesPie = ({ salesData }) => {
return (
<ChartPanel title="カテゴリ別売上">
<FlexPie
itemsSource={salesData}
binding="sales"
bindingName="name"
innerRadius={0.7}
style={{ height: '290px' }}
palette={[
'rgba(171, 125,246, 1)',
'rgba(38, 193, 201, 1)',
'rgba(129, 201, 38, 1)',
'rgba(250, 202, 0, 1)',
]}
/>
</ChartPanel>
);
};
・・・(中略)・・・

データグリッド(FlexGrid)の定義
以下の部分では、本日の取引一覧をFlexGridで表示しています。FlexGridをDataPanel
でラップし、さらにFlexGridの各種プロパティを設定しています。FlexGridの列や列ヘッダーは設定されたデータソースに応じて自動的に設定が可能ですが、今回は設定を細かく制御するためにFlexGridColumn
を追加しています。width
にはスターサイズ指定オプションというFlexGridで動的にサイズを指定する方法で列の幅を定義しています。詳しくは製品ヘルプをご覧ください。
・・・(中略)・・・
// 本日の取引一覧をグリッドで表示するコンポーネント
const TransactionList = ({ transactions }) => {
return (
<DataPanel title="本日の取引">
<FlexGrid
style={{ width: '100%' }}
itemsSource={transactions}
selectionMode="Row"
alternatingRowStep={1}
>
<FlexGridColumn header="クライアント名" binding="client" width="2*" />
<FlexGridColumn header="説明" binding="description" width="3*" />
<FlexGridColumn header="合計" binding="value" width="1*" />
<FlexGridColumn header="数量" binding="itemCount" width="1*" />
</FlexGrid>
</DataPanel>
);
};
・・・(中略)・・・

スタイルの設定
最後に「arc/App.css」にスタイルを追加します。
/* 全体背景 */
html,
body {
background: rgb(0 193 213 / 1);
}
/* 見出しのスタイル */
h5 {
color: white !important;
padding: 8px;
}
/* ダッシュボードのパネル・行の余白 */
.dashboardRow {
margin-top: 20px;
}
.dashboardPanel {
margin-top: 20px;
}
/* カードの枠線を消す */
.card {
border: none;
}
/* カードの中身の背景色と余白 */
.card-body {
background: rgb(19 124 144 / 1);
padding: 0px;
}
/* カードタイトルの余白 */
.card-title {
margin: 0.2rem;
}
/* Bootstrapのbg-lightを上書き(背景色変更) */
.bg-light {
background-color: rgb(19 124 144 / 1) !important;
}
/* ゲージ */
.gauge {
min-height: 290px;
background: rgb(21 96 115 / 1);
padding: 10px;
padding-top: 40px;
}
.gauge .wj-value {
fill: white;
font-size: 64px;
font-weight: 700;
}
.gauge :is(.wj-min, .wj-max) {
fill: rgb(135 166 191 / 1);
}
.gauge .wj-pointer {
fill: rgb(171 125 246 / 1);
}
.gauge .wj-face path {
fill: rgb(135 166 191 / 1);
stroke-width: 0px;
}
/* --- フレックスチャート --- */
.wj-flexchart,
.wj-flexpie {
padding: 10px;
margin: 0px;
border: none !important;
background: rgb(21 96 115 / 1) !important;
}
/* Wijmoテーマによるデフォルトの下余白を削除 */
.wj-control:is(.wj-flexchart, .wj-flexpie) {
margin-bottom: 0 !important;
}
/* カード内でチャートの背景をクリップ */
.dashboardPanel .card-body {
overflow: hidden;
}
/* Wijmoによって生成された白いプロット矩形/境界を削除 */
:is(.wj-flexchart, .wj-flexpie) svg .wj-plot-area > :is(path, rect) {
stroke: none !important;
fill: transparent !important;
}
/* SVGの背景を透明にしてカード色を反映 */
:is(.wj-flexchart, .wj-flexpie) svg {
background: transparent !important;
}
.wj-flexchart .wj-axis-x .wj-line {
stroke: rgb(135 166 191 / 1);
stroke-width: 1px;
}
.wj-flexchart .wj-axis-y .wj-gridline {
stroke: rgb(135 166 191 / 1);
stroke-width: 1px;
}
/* ダーク背景でのラベルの視認性向上 */
:is(.wj-flexchart, .wj-flexpie, .wj-legend) .wj-label,
.wj-flexchart :is(.wj-axis-x, .wj-axis-y) .wj-label {
fill: #e6f4f8 !important; /* brighter text */
}
:is(.wj-flexchart, .wj-flexpie) .wj-label {
fill: rgb(135 166 191 / 1);
}
.wj-flexchart .wj-axis-x .wj-line {
stroke: rgb(135 166 191 / 1);
stroke-width: 1px;
}
.wj-flexchart .wj-axis-y .wj-gridline {
stroke: rgb(135 166 191 / 1);
stroke-width: 1px;
}
.wj-legend .wj-label {
fill: rgb(135 166 191 / 1);
}
/* --- フレックスグリッド --- */
.wj-flexgrid,
.wj-flexgrid :is(.wj-root, .wj-cells, .wj-colheaders, .wj-rowheaders, .wj-topleft) {
background: rgb(21 96 115) !important;
}
.wj-flexgrid {
border: none;
border-radius: 0;
color: #fff;
}
/* グリッド全体の文字色を白に強制 */
.wj-flexgrid .wj-cell {
color: #fff !important;
}
/* ヘッダー部の背景色・文字色・太字(Wijmo/Bootstrapの上書き) */
.wj-flexgrid .wj-header,
.wj-flexgrid :is(.wj-colheaders, .wj-rowheaders, .wj-topleft) .wj-cell {
background: rgb(19 88 109) !important;
color: #fff !important;
font-weight: 700;
}
/* 選択行・複数選択行の背景色 */
.wj-flexgrid .wj-state-selected {
background: rgb(171 125 246) !important;
}
.wj-flexgrid .wj-state-multi-selected {
background: rgb(171 125 246 / 0.3) !important;
}
/* 交互行の背景色(ダークベース上) */
.wj-flexgrid .wj-cell:not(:is(.wj-header, .wj-group, .wj-state-selected, .wj-state-multi-selected)) {
background: rgb(255 255 255 / 0.2);
}
.wj-flexgrid .wj-alt:not(:is(.wj-header, .wj-group, .wj-state-selected, .wj-state-multi-selected)) {
background: rgb(255 255 255 / 0.3);
}
動作確認
再度アプリケーションを実行すると、以下のようにゲージやチャート、データグリッドを含むダッシュボードを表示することができます。

今回作成したアプリケーションは以下よりダウンロード可能です。
さいごに
Wijmoの各種コントロールを使用して、ReactとBootstrapでデータを可視化するダッシュボード画面を作成する方法をご紹介しました。
製品サイトでは、Wijmoの機能を手軽に体験できるデモアプリケーションやトライアル版も公開しておりますので、こちらもご確認ください。
また、ご導入前の製品に関するご相談、ご導入後の各種サービスに関するご質問など、お気軽にお問合せください。