React×WijmoでOpenWeatherMap APIから取得したデータを可視化してみた

「React(リアクト)」はMeta(旧Facebook)が開発したJavaScriptフレームワークです。世界中のIT技術者1万人以上から取ったアンケートの結果をまとめた「State of JavaScript」において、2016年から2022年まで常にトップの利用率を維持しているフロントエンドフレームワークです。

JavaScript開発ライブラリ「Wijmo(ウィジモ)」はReactをサポートしており、Reactの標準的な方法でグリッド/入力/チャートなどのエンタープライズ開発で必要とされるWijmoのコンポーネントを利用することができます。

本記事では、数あるWijmoのコントロール群の中から、データの可視化に役立つ「ゲージ」コントロールをReactアプリケーションに組み込み、APIから取得した気象データを可視化する方法をご紹介します。

Wijmoを組み込んだデータを可視化

ViteでReactアプリケーションの作成

Reactのアプリを作成する方法はいくつかありますが、今回はビルドツール「Vite」を使用します。

以下のコマンドを実行して、ベースとなるReactアプリケーションを作成します。今回は「react」のオプションを指定してReactとJavaScriptのアプリケーションをスキャフォールドします。
※ 使用可能なテンプレートはこちらをご覧ください。

npm create vite wijmo-gauge-app -- --template react

次に以下のコマンドを実行してアプリケーションプロジェクトのフォルダに移動し、必要なパッケージのインストールを行います。

cd wijmo-gauge-app
npm install

パッケージがインストールされたら、以下のコマンドを実行してReactアプリケーションを起動します。

npm run dev

ブラウザで「http://localhost:5173/」を参照すると以下のように開発サーバーでReactアプリケーションの実行を確認できます。

Reactアプリケーションの実行

アプリケーションの起動を確認したらCtrl+Cキーを押して終了しておきます。

Wijmoのインストール

ベースとなるReactのアプリケーションが作成されたら、「npm install」コマンドを実行して、Wijmoのインストールを行います。WijmoではReact専用のパッケージが提供されているので、そちらをアプリケーションにインストールします。また、スタイルの調整のためCSSフレームワークの「Bootstrap」もインストールします。

npm install @grapecity/wijmo.react.all
npm install bootstrap

OpenWeatherMapのAPIキーの取得

ゲージに表示するデータには「OpenWeatherMap」が提供している気象データを使用します。

上記のリンクからOpenWeatherMapのWebサイトにアクセスし、右上の「Sign in」のメニューを押下します。

OpenWeatherMapにサインイン

すでにアカウントがある場合はログインし、アカウントがない場合は「Create an Account」のメニューからアカウントを作成します。

OpenWeatherMapにサインイン(2)

ログインができたら右上の「My API keys」のメニューからAPIキーを取得します。

OpenWeatherMapのAPIキー

アプリケーションにWijmoの組み込み

以上で事前の準備が全て完了したので、次にアプリケーションにゲージの組み込みを行っていきます。「src\WeatherComponent.jsx」を新たに作成し、以下のように記述します。
※ ライセンスキーを設定しない場合トライアル版を示すメッセージが表示されます。ライセンスキーの入手や設定方法についてはこちらをご覧ください。

import React, { useState, useEffect, useCallback } from 'react';
import * as wjCore from "@grapecity/wijmo";
import * as wjGauge from '@grapecity/wijmo.react.gauge';
import { ShowText, RadialGauge as rg } from '@grapecity/wijmo.gauge';
import '@grapecity/wijmo.styles/wijmo.css';
import '@grapecity/wijmo.cultures/wijmo.culture.ja';
import './App.css';
import 'bootstrap/dist/css/bootstrap.css';

wjCore.setLicenseKey('ここにWijmoのライセンスキーを設定します');

const WeatherComponent = (props) => {
    const [weatherData, setWeatherData] = useState(null);
    const apiKey = 'ここに作成したOpenWeatherMapのAPIキーを設定します';
    const city = props.city;

    const getTextCallback = useCallback((gauge, part, value, text) => {
        return `${text}℃`;
    });

    useEffect(() => {
        const fetchWeatherData = async () => {
            try {
                const response = await fetch(
                    `https://api.openweathermap.org/data/2.5/weather?lang=ja&q=${city}&units=metric&appid=${apiKey}`
                );
                const data = await response.json();

                setWeatherData(data);
            } catch (error) {
                console.error('Error fetching weather data:', error);
            }
        };

        fetchWeatherData();
    }, [city, apiKey]);

    return (
        <div>
            {weatherData && (
                <>
                    <div className="tile">
                        <div className="tile-container">
                            <div className="tile-header">
                                <h2>{weatherData.name}</h2>
                                <img
                                    className="iconImg"
                                    src={`https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`}
                                />
                            </div>

                            <div className="tile-content">
                                <wjGauge.RadialGauge
                                    autoScale={false}
                                    thickness={0.2}
                                    showText={ShowText.Value}
                                    getText={getTextCallback}
                                    min={-20}
                                    max={50}
                                    value={weatherData.main.temp}
                                    startAngle={-45}
                                    sweepAngle={270}
                                    showTicks={true}
                                    showTickText={true}
                                    tickSpacing={5}
                                    isReadOnly={true}
                                    showRanges={true}
                                    needleLength={'Inner'}
                                    needleElement={rg.createNeedleElement([
                                        { x: 40, y: 15 },
                                        { x: 90, y: 0 },
                                    ])}
                                >
                                    <wjGauge.Range wjProperty="pointer" thickness={0} />
                                    <wjGauge.Range min={-20} max={-10} color="MidnightBlue" />
                                    <wjGauge.Range min={-10} max={0} color="DarkBlue" />
                                    <wjGauge.Range min={0} max={10} color="LightBlue" />
                                    <wjGauge.Range min={10} max={20} color="Gold" />
                                    <wjGauge.Range min={20} max={30} color="GoldenRod" />
                                    <wjGauge.Range min={30} max={40} color="FireBrick" />
                                    <wjGauge.Range min={40} max={50} color="DarkRed" />
                                </wjGauge.RadialGauge>
                            </div>
                        </div>
                    </div>
                </>
            )}
        </div>
    );
};
export default WeatherComponent;

上記のコードでは、先ほど取得したOpenWeatherMapのAPIキーを使用し、無料で使える現在の気象データを返却するAPIをコールし、コンポーネントの引数(props)で受け取った都市名の気象データを取得します。

・・・(中略)・・・
const WeatherComponent = (props) => {
    const [weatherData, setWeatherData] = useState(null);
    const apiKey = 'ここに作成したOpenWeatherMapのAPIキーを設定します';
    const city = props.city;

・・・(中略)・・・

    useEffect(() => {
        const fetchWeatherData = async () => {
            try {
                const response = await fetch(
                    `https://api.openweathermap.org/data/2.5/weather?lang=ja&q=${city}&units=metric&appid=${apiKey}`
                );
                const data = await response.json();

                setWeatherData(data);
            } catch (error) {
                console.error('Error fetching weather data:', error);
            }
        };

        fetchWeatherData();
    }, [city, apiKey]);
・・・(中略)・・・

取得したデータはWijmoのゲージコントロールとバインドし、「円形ゲージ」として表示します。コールバック関数を使用して、表示する気温の数値に「℃」の文字列を連結して表示している点がポイントです。

・・・(中略)・・・
const getTextCallback = useCallback((gauge, part, value, text) => {
    return `${text}℃`;
});
・・・(中略)・・・
<div className="tile-content">
    <wjGauge.RadialGauge
        autoScale={false}
        thickness={0.2}
        showText={ShowText.Value}
        getText={getTextCallback}
・・・(中略)・・・

円形ゲージに設定している各種プロパティについてはAPIリファレンスをご覧ください。

次に「src\App.jsx」を以下のように書き換えます。先ほど作成したWeatherComponentを表示する都市の分mapメソッドで繰り返し読み込み、引数として都市名を渡します。

import React from 'react';
import WeatherComponent from './WeatherComponent';

const city = ['Sapporo', 'Tokyo', 'Fukuoka'];

const cityList = city.map((item, index) => {
  return <WeatherComponent key={index} city={item} />
})

function App() {

  return (
    <div className="App">
      <header className="App-header">
        <h1>現在の天気</h1>
      </header>

      <main className="city-list">
        {cityList}
      </main>
    </div>
  );
}

export default App;

次に「src\App.css」を以下のように設定し、各要素のスタイルを調整します。

h2 {
  text-align: center;
}

.App-header {
  text-align: center;
  margin-top: 2rem;
  margin-bottom: 2rem;
}

.iconImg {
  height: 100px;
  width: 100px;
}

.tile {
	background: white;
	border-radius: 0.5rem;
	box-sizing: border-box;
	margin-right: 15px;
	margin-bottom: 15px;
	box-shadow: 0 1px 2px rgba(55, 63, 66, 0.07), 0 2px 4px rgba(55, 63, 66, 0.07), 0 4px 8px rgba(55, 63, 66, 0.07),
		0 8px 16px rgba(55, 63, 66, 0.07), 0 16px 24px rgba(55, 63, 66, 0.07), 0 24px 32px rgba(55, 63, 66, 0.07);
}

.tile .tile-container {
	border-bottom: 1px solid #e0e0e0;
	padding: 0.75rem 1rem;
}

.tile .tile-header {
	padding: 0.125rem;
	opacity: 0.75;
	text-align: center;
	font-size: 20px;
}

.tile .tile-content {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	height: 90%;
}

.city-list{
	display: flex;
	flex-wrap: wrap;
	width: 1050px;
	margin: auto;
}

最後に仕上げとして「src\index.css」に設定されているデフォルトのスタイルを全て削除します。

(デフォルトのスタイルを削除)

以上の手順で、実装は完了です。再び「npm run dev」コマンドを実行して「http://localhost:5173/」に接続すると、Wijmoのゲージ上にAPIから取得した各都市の気象データ(現在の天気と気温)が表示されます。

Wijmoを組み込んだアプリケーションの起動(1)

「src\App.jsx」において、配列に設定する都市名を増やすと表示するデータも連動して増えます。

import React from 'react';
import WeatherComponent from './WeatherComponent';

const city = ['Sapporo', 'Sendai', 'Tokyo', 'Nagoya', 'Osaka', 'Fukuoka'];
・・・(中略)・・・
Wijmoを組み込んだアプリケーションの起動(2)

さいごに

以上がWijmoの「ゲージ」コントロールをReactアプリケーションに組み込み、OpenWeatherMapのAPIから取得した気象データを可視化する方法でした。

製品サイトでは、Wijmoの機能を手軽に体験できるデモアプリケーションやトライアル版も公開しておりますので、こちらもご確認ください。

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

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