JavaScript

Apache ECharts レーダーチャート入門|JavaScriptで作る複数系列の比較グラフ

みなと

この記事は、Apache EChartsを使ったレーダーチャートの実装解説です。ECharts自体の概要やセットアップ方法は、過去の折れ線グラフ記事でまとめています。EChartsが初めての方は、先にそちらをお読みください。

あわせて読みたい
Apache ECharts 折れ線グラフ入門|最小サンプルから実務レベルに仕上げる手順
Apache ECharts 折れ線グラフ入門|最小サンプルから実務レベルに仕上げる手順
あわせて読みたい
Apache ECharts 棒グラフ入門|縦棒・横棒の実装からボタン切り替えまで
Apache ECharts 棒グラフ入門|縦棒・横棒の実装からボタン切り替えまで
あわせて読みたい
Apache ECharts 円グラフ入門|円・ドーナツの実装からボタン切り替えまで
Apache ECharts 円グラフ入門|円・ドーナツの実装からボタン切り替えまで

Apache ECharts 公式サイト

この記事では、レーダーチャートの実装を中心に、デザイン調整・レスポンシブ対応・ボタン切り替え、そして複数系列を重ねた比較表示まで一通り解説します。

完成デモを触ってみよう

まずは完成デモを見て、最終的にどんな形を目指すか確認してみましょう。ボタンを押すと、ページ別のUX/UI評価レーダーチャート(リニューアル前後の比較・※数値はサンプル)を表示・切り替えできます。

ボタンを押すと
グラフが表示されます

PC幅で見ると、レーダーがコンテナの中央に大きく配置され、6つの評価軸(使いやすさ・視認性・情報整理・デザイン性・アクセシビリティ・レスポンシブ対応)が等間隔に並びます。「リニューアル前(青)」と「リニューアル後(ピンク)」の2つの多角形が重なって描画され、塗りつぶしの透明度を低めにしているので、両方の形状が判別できる見た目になっています。

スマホ幅で見ると、レーダーは小さめに表示されます。また、長めの項目名(「アクセシビリティ」「レスポンシブ対応」)は画面外にはみ出さないよう、PC用とは別に改行入りの軸ラベルを用意しています。

コード全体(HTML / CSS / JavaScript)

ここからは実際にコードを見ていきます。HTML・CSSはコードとポイントをあわせて解説します。JavaScriptは全体を掲載してから、次のセクションで詳しく解説します。

HTML

<!-- 切り替えボタンのエリア -->
<div class="chart-switcher">
  <button id="serviceChartBtn" class="chart-tab" type="button">サービス紹介ページ</button>
  <button id="contactChartBtn" class="chart-tab" type="button">お問い合わせページ</button>
</div>

<!-- グラフ表示エリア -->
<div id="echartsContainer" class="echarts-container">
  <!-- グラフが描画される前に表示するプレースホルダー -->
  <div class="chart-placeholder">
    <p class="chart-placeholder-text">ボタンを押すと<br>グラフが表示されます</p>
  </div>
</div>

HTMLはシンプルな2つのブロックで構成されています。

切り替えボタンのエリアには、id を付けた2つの button を並べています。この id をJavaScript側で取得して、クリックイベントに紐づけます。

グラフ表示エリアは id=”echartsContainer” の div で、EChartsはこの要素をコンテナとしてグラフを描画します。初期状態ではプレースホルダー(「ボタンを押すとグラフが表示されます」)を表示しておき、ボタンを押したタイミングでグラフに置き換わります。

スワン
スワン

EChartsのグラフ描画に必須なのは、コンテナとなる div(id=”echartsContainer”)だけです。ボタンやプレースホルダーは今回のデモ用の実装なので、ただグラフを表示したいだけであれば、コンテナのみで問題ありません。

CSS

/* ===============================
   切り替えボタンエリア
   =============================== */
.chart-switcher {
  display: flex;
  justify-content: center;
}

@media (min-width: 768px) {
  .chart-switcher {
    gap: 30px;
  }
}

@media (max-width: 767px) {
  .chart-switcher {
    gap: 15px;
  }
}

/* ボタンの基本スタイル */
.chart-tab {
  display: block;
  position: relative;
  border: none;
  border-radius: 5px;
  padding: 15px 0;
  background: #c11a51;
  color: #fff;
  font: inherit;
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
  cursor: pointer;
  appearance: none;
  transition: background-color 300ms, color 300ms;
}

@media (min-width: 768px) {
  .chart-tab {
    width: 200px;
    font-size: 16px;
  }
}

@media (max-width: 767px) {
  .chart-tab {
    flex: 1;
    width: 100%;
    font-size: 15px;
  }
}

/* 選択中ボタンの下に表示する三角形 */
.chart-tab::before {
  content: "";
  display: block;
  position: absolute;
  left: 50%;
  bottom: -12px;
  width: 15px;
  height: 12px;
  background: #f9e8ed;
  clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 300ms;
}

/* ホバー時(PCのみ) */
@media (min-width: 768px) {
  .chart-tab:hover {
    background: #890631;
  }
}

/* 選択中のボタン */
.chart-tab.is-active {
  background: #f9e8ed;
  color: #c11a51;
  pointer-events: none;
}

/* アクティブ時だけ三角を表示 */
.chart-tab.is-active::before {
  opacity: 1;
}

/* ===============================
   グラフエリア
   =============================== */
@media (min-width: 768px) {
  .echarts-container {
    height: 450px; /* PCのチャート高さ */
    margin-top: 40px;
  }
}

@media (max-width: 767px) {
  .echarts-container {
    height: 380px; /* SPのチャート高さ */
    margin-top: 30px;
  }
}

/* プレースホルダー(グラフ描画前の表示) */
.chart-placeholder {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  border-radius: 5px;
  background-color: rgba(68, 102, 206, 0.09);
  text-align: center;
}

.chart-placeholder-text {
  color: #31345e;
  font-weight: 700;
  line-height: 1.6;
  opacity: 0.5;
}

@media (min-width: 768px) {
  .chart-placeholder-text {
    font-size: 26px;
  }
}

@media (max-width: 767px) {
  .chart-placeholder-text {
    font-size: 20px;
  }
}

CSSも大きく2つのブロックに分かれています。

ボタンエリアは display: flex で横並びにしています。is-active クラスが付いたボタンは背景色と文字色が反転し、::before 擬似要素で下向きの三角形を表示します。pointer-events: none を合わせて指定することで、選択中のボタンを押せない状態にしています。

グラフエリアはEChartsの仕様上、高さをCSSで指定する必要があります。高さを指定しないとグラフが表示されないため、必ず設定しておきましょう。

スワン
スワン

HTMLと同様に、EChartsのグラフ描画に必須なCSSはコンテナの高さ指定だけです。ボタンやプレースホルダーのスタイルは今回のデモ用の実装です。

JavaScript

document.addEventListener('DOMContentLoaded', () => {
  const btnService = document.getElementById('serviceChartBtn');
  const btnContact = document.getElementById('contactChartBtn');
  const chartDom = document.getElementById('echartsContainer');

  // コンテナが存在しない場合は処理を止める(エラー防止)
  if (!chartDom) return;

  let myChart = null;

  // 評価項目(両グラフ共通)。レーダー軸の名前と最大値を定義
  // SPでは長い項目名が画面外にはみ出すため、SP用は改行入りで別途用意
  const indicatorsPC = [
    { name: '使いやすさ', max: 10 },
    { name: '視認性', max: 10 },
    { name: '情報整理', max: 10 },
    { name: 'デザイン性', max: 10 },
    { name: 'アクセシビリティ', max: 10 },
    { name: 'レスポンシブ対応', max: 10 }
  ];
  const indicatorsSP = [
    { name: '使いやすさ', max: 10 },
    { name: '視認性', max: 10 },
    { name: '情報整理', max: 10 },
    { name: 'デザイン性', max: 10 },
    { name: 'アクセシ\nビリティ', max: 10 },
    { name: 'レスポンシブ\n対応', max: 10 }
  ];

  // サービス紹介ページのリニューアル前後スコア(indicatorsと同じ順序)
  const serviceBefore = [6, 5, 5, 6, 7, 7];
  const serviceAfter  = [8, 9, 9, 9, 8, 8];

  // お問い合わせページのリニューアル前後スコア(indicatorsと同じ順序)
  const contactBefore = [5, 6, 7, 6, 4, 5];
  const contactAfter  = [9, 7, 8, 7, 9, 9];

  // 2つのグラフで共通する設定をまとめたベースoption
  const baseOption = {
    // 系列の色(data配列の順番に適用される)
    // 0: リニューアル前(青)/1: リニューアル後(ピンク)
    color: ['#4466ce', '#c11a51'],
    // グラフ全体の文字スタイル
    textStyle: {
      color: '#333',
      fontFamily: '"Noto Sans JP", sans-serif',
      fontSize: 14,
      fontWeight: 300
    },
    // タイトルの共通設定(タイトル本文はページごと、フォントサイズはmediaで切り替え)
    title: {
      top: 0,
      left: 'center',
      textStyle: {
        lineHeight: 26
      }
    },
    // 凡例の共通設定(itemGapはmedia側で切り替え)
    legend: {
      bottom: 0,
      left: 'center',
      orient: 'horizontal',
      itemWidth: 16,
      itemHeight: 12,
      selectedMode: false
    },
    // レーダー軸の共通設定(indicator・センター・半径・フォントサイズはmedia側で切り替え)
    radar: {
      // 軸ラベル(項目名)のスタイル
      axisName: {
        lineHeight: 17
      },
      // 軸線(中心から外側に伸びる線)
      axisLine: {
        lineStyle: { color: 'rgba(0, 0, 0, 0.15)' }
      },
      // 分割線(同心多角形のライン)
      splitLine: {
        lineStyle: { color: 'rgba(0, 0, 0, 0.15)' }
      },
      // 分割エリア(同心多角形の塗り)。薄い縞模様にして背景を整える
      splitArea: {
        show: true,
        areaStyle: {
          color: ['rgba(248, 248, 252, 0.5)', 'rgba(255, 255, 255, 0.5)']
        }
      }
    },
    // チャートの幅に応じてレイアウトを切り替え
    media: [
      {
        // PC幅:各要素を標準サイズで表示
        query: { minWidth: 740 },
        option: {
          title: { textStyle: { fontSize: 18 } },
          legend: {
            itemGap: 30
          },
          radar: {
            indicator: indicatorsPC, // 軸の項目(PC用)
            center: ['50%', '230px'], // 中心位置 [水平, 垂直]
            radius: '140px', // 半径(レーダーの大きさ)
            axisName: { fontSize: 14 } // 軸ラベルのフォントサイズ
          }
        }
      },
      {
        // スマホ幅:各要素を縮小して表示
        query: { maxWidth: 739 },
        option: {
          title: { textStyle: { fontSize: 16 } },
          legend: {
            itemGap: 20
          },
          radar: {
            indicator: indicatorsSP, // 軸の項目(SP用)
            center: ['50%', '205px'], // 中心位置 [水平, 垂直]
            radius: '95px', // 半径(レーダーの大きさ)
            axisName: { fontSize: 12 } // 軸ラベルのフォントサイズ
          }
        }
      }
    ]
  };

  // サービス紹介ページのグラフoption(baseOptionに差分を追加)
  const optionService = {
    ...baseOption,
    series: [{
      type: 'radar',
      lineStyle: { width: 1 },
      areaStyle: { opacity: 0.2 },
      symbolSize: 5,
      data: [
        {
          value: serviceBefore,
          name: 'リニューアル前',
        },
        {
          value: serviceAfter,
          name: 'リニューアル後',
        }
      ]
    }],
    // タイトル本文はmediaで媒体ごとに指定(SP→PC切り替え時に改行が戻るよう両方を明示)
    media: [
      ...baseOption.media,
      {
        query: { minWidth: 740 },
        option: {
          title: { text: 'サービス紹介ページ UX/UI評価(リニューアル前後)' }
        }
      },
      {
        query: { maxWidth: 739 },
        option: {
          title: { text: 'サービス紹介ページ UX/UI評価\n(リニューアル前後)' }
        }
      }
    ]
  };

  // お問い合わせページのグラフoption(baseOptionに差分を追加)
  const optionContact = {
    ...baseOption,
    series: [{
      type: 'radar',
      lineStyle: { width: 1 },
      areaStyle: { opacity: 0.2 },
      symbolSize: 5,
      data: [
        {
          value: contactBefore,
          name: 'リニューアル前',
        },
        {
          value: contactAfter,
          name: 'リニューアル後',
        }
      ]
    }],
    // タイトル本文はmediaで媒体ごとに指定(SP→PC切り替え時に改行が戻るよう両方を明示)
    media: [
      ...baseOption.media,
      {
        query: { minWidth: 740 },
        option: {
          title: { text: 'お問い合わせページ UX/UI評価(リニューアル前後)' }
        }
      },
      {
        query: { maxWidth: 739 },
        option: {
          title: { text: 'お問い合わせページ UX/UI評価\n(リニューアル前後)' }
        }
      }
    ]
  };

  // グラフを描画し、押したボタンをアクティブにする関数
  function showChart(optionToSet, activeBtn) {
    // まだ初期化していない場合のみecharts.init()を呼ぶ(二重初期化防止)
    if (!myChart) {
      myChart = echarts.init(chartDom);
    }
    // 第2引数のtrueで前の設定を残さず新しいoptionに切り替える
    myChart.setOption(optionToSet, true);

    // ボタンのアクティブ状態を切り替える
    [btnService, btnContact].forEach(btn => btn.classList.remove('is-active'));
    activeBtn.classList.add('is-active');
  }

  btnService.addEventListener('click', () => showChart(optionService, btnService));
  btnContact.addEventListener('click', () => showChart(optionContact, btnContact));

  // 画面サイズ変更時にグラフを再描画(描画済みの場合のみ)
  window.addEventListener('resize', () => {
    if (myChart) myChart.resize();
  });
});

JavaScript のポイント解説

JavaScript の全体構造

このコードは、大きく4つのブロックで構成されています。

ブロック役割
baseOption2つのグラフで共通する設定をまとめたベース
optionService と optionContactページごとのグラフ設定(baseOption に差分を追加)
showChart と addEventListenerグラフを描画してボタンのアクティブ状態を切り替える関数と、ボタンのクリックイベントの紐付け
resize画面サイズ変更時にグラフを再描画する処理

baseOption を土台にして、ページごとの差分(タイトルテキスト・データ)を乗せた optionService / optionContact を用意し、ボタンを押したときに showChart で切り替える——これがコード全体の基本的な流れです。

1)baseOption:共通設定をまとめる

const baseOption = {
  color: [ ... ],
  textStyle: { ... },
  title: { ... },
  legend: { ... },
  radar: { ... },
  media: [ ... ]
};

2つのグラフで共通する設定——系列の色・文字スタイル・タイトル設定・凡例・レーダー軸の見た目・レスポンシブ——をすべて baseOption にまとめています。タイトルテキストとデータ(series)はページごとに異なるため、baseOption には含めていません。グラフの数が増えても、baseOption を変えれば全体に反映されるので管理が楽になります。

baseOption の中身を項目ごとに見ていきます。

color

color: ['#4466ce', '#c11a51']

レーダーの各系列に使う色を、配列で順番に指定します。series.data 配列の順序に対応して、最初の系列に #4466ce(青)、次の系列に #c11a51(ピンク)が割り当てられます。

今回は series.data に「リニューアル前 → リニューアル後」の順で並べているため、リニューアル前が青、リニューアル後がピンクで描画されます。

textStyle

textStyle: {
  color: '#333',
  fontFamily: '"Noto Sans JP", sans-serif',
  fontSize: 14,
  fontWeight: 300
}

グラフ内の文字(タイトル・凡例・軸ラベルなど)に共通で効く文字スタイルです。色・フォント・サイズ・ウェイトをサイトのデザインに合わせて指定します。

title

title: {
  top: 0,
  left: 'center',
  textStyle: {
    lineHeight: 26
  }
}

タイトルの共通設定です。top: 0 でコンテナの上端、left: 'center' で水平方向の中央に配置します。textStyle.lineHeight: 26 は、スマホ幅でタイトルが2行になったときの行間です。

タイトルテキスト(text プロパティ)とフォントサイズは別の場所で指定します。タイトルテキストはページごとに違うため optionService / optionContact 側の media で、フォントサイズはPC/SPで違うため baseOption.media 側で指定します。

legend

legend: {
  bottom: 0,
  left: 'center',
  orient: 'horizontal',
  itemWidth: 16,
  itemHeight: 12,
  selectedMode: false
}

凡例の設定です。bottom: 0left: 'center' でコンテナの下中央に配置し、orient: 'horizontal' で横並びにします。itemWidth / itemHeight は凡例アイコンのサイズです。

selectedMode: false は、凡例クリックによる項目の表示・非表示の切り替えを無効にする設定です。今回は2系列とも常に見えていてほしいので無効にしています。

凡例どうしの間隔(itemGap)はPC/SPで変えたいため、media 側で指定しています。

radar

radar: {
  axisName: {
    lineHeight: 17
  },
  axisLine: {
    lineStyle: { color: 'rgba(0, 0, 0, 0.15)' }
  },
  splitLine: {
    lineStyle: { color: 'rgba(0, 0, 0, 0.15)' }
  },
  splitArea: {
    show: true,
    areaStyle: {
      color: ['rgba(248, 248, 252, 0.5)', 'rgba(255, 255, 255, 0.5)']
    }
  }
}

レーダー軸の共通設定です。

axisName は軸ラベル(項目名)のスタイルです。lineHeight: 17 はスマホで項目名が2行に改行されたときの行間です。

axisLine は中心から外側に伸びる軸線、splitLine は同心多角形の分割線です。どちらも控えめな薄いグレーで指定しています。

splitArea は分割エリアの塗りです。show: true で表示を有効にして、color に2色の配列を渡すことで、同心多角形が交互に色違いの帯になります。今回はほぼ白の2色を指定して、目立たない縞模様にしてレーダー全体の背景を整えています。

軸の項目自体(indicator)、レーダーの位置(center)、大きさ(radius)、軸ラベルのフォントサイズはPC/SPで変えたいため、media 側で指定しています。

media

media: [
  {
    query: { minWidth: 740 },
    option: {
      title: { textStyle: { fontSize: 18 } },
      legend: { itemGap: 30 },
      radar: {
        indicator: indicatorsPC,
        center: ['50%', '230px'],
        radius: '140px',
        axisName: { fontSize: 14 }
      }
    }
  },
  {
    query: { maxWidth: 739 },
    option: {
      title: { textStyle: { fontSize: 16 } },
      legend: { itemGap: 20 },
      radar: {
        indicator: indicatorsSP,
        center: ['50%', '205px'],
        radius: '95px',
        axisName: { fontSize: 12 }
      }
    }
  }
]

media は、チャートの幅に応じてレイアウトを切り替えるための仕組みです。CSSのメディアクエリに近い感覚で使えますが、判定するのは「画面幅」ではなく「チャート(コンテナ)の幅」です。

PC幅とスマホ幅で、それぞれ次の要素を切り替えています。

  • タイトルのフォントサイズ(PC:18px、SP:16px)
  • 凡例の項目間隔(PC:30px、SP:20px)
  • レーダーの軸の項目(indicator:PC用・SP用)
  • レーダーの中心位置(center)
  • レーダーの半径(radius)
  • 軸ラベルのフォントサイズ(PC:14px、SP:12px)

軸の項目自体にPC/SPで違いがあるのは、長めの項目名がスマホ幅で画面外にはみ出すのを防ぐためです。SP用は次のように、長い項目名に改行を入れています。

const indicatorsPC = [
  { name: '使いやすさ', max: 10 },
  ...
  { name: 'アクセシビリティ', max: 10 },
  { name: 'レスポンシブ対応', max: 10 }
];
const indicatorsSP = [
  { name: '使いやすさ', max: 10 },
  ...
  { name: 'アクセシ\nビリティ', max: 10 },
  { name: 'レスポンシブ\n対応', max: 10 }
];

indicator は「軸の項目と最大値」を定義する配列です。{ name, max } のオブジェクトを並べることで、各軸の項目名と上限値(今回は全軸10点満点)を指定します。ECharts は name 内の \n を改行として描画してくれるため、これで2行表示にできます。

2)optionService と optionContact:差分だけを上書きする

const optionService = {
  ...baseOption,
  series: [ ... ],
  media: [ ... ]
};

スプレッド構文(...baseOption)で共通設定を継承して、その上から series と media だけ書き換えるパターンです。サービス紹介ページ用とお問い合わせページ用で、それぞれ違う部分だけ差分として書きます。

optionService の中身を項目ごとに見ていきます。

series

series: [{
  type: 'radar',
  lineStyle: { width: 1 },
  areaStyle: { opacity: 0.2 },
  symbolSize: 5,
  data: [
    { value: serviceBefore, name: 'リニューアル前' },
    { value: serviceAfter, name: 'リニューアル後' }
  ]
}]

実際に描画するレーダーチャートの設定です。

type: 'radar' でレーダーチャートを描画することを示します。

lineStyle は外周線のスタイル、areaStyle は内部の塗りつぶし、symbolSize は各頂点のドットのサイズです。これらを series レベル(data の外側)に書くと、data 配列のすべての系列に共通で適用されます。

data は実際の値です。{ value: 値の配列, name: 系列名 } のオブジェクトを、系列の数だけ並べます。value の配列は indicator と同じ順序で値を入れます。

ここで意識しておきたいのが、data 配列の順序です。

レーダーチャートで複数系列を重ね描画したとき、重なり順は data 配列の順序で決まります。先に書いたものが下層、後に書いたものが上層に描画されます。今回は「リニューアル前 → リニューアル後」の順なので、リニューアル後が手前に描画されます。

リニューアル後のほうが面積の大きい多角形になりますが、areaStyle.opacity を 0.2 と低めにしているため、奥にあるリニューアル前の形状も判別できる見た目になります。

media

media: [
  ...baseOption.media,
  {
    query: { minWidth: 740 },
    option: {
      title: { text: 'サービス紹介ページ UX/UI評価(リニューアル前後)' }
    }
  },
  {
    query: { maxWidth: 739 },
    option: {
      title: { text: 'サービス紹介ページ UX/UI評価\n(リニューアル前後)' }
    }
  }
]

タイトルテキストを、PC幅とSP幅で切り替えるための media 設定です。

...baseOption.media で共通設定を展開した後、ページごとのタイトルテキスト上書きを2つ追加しています。PC幅では1行のタイトル、SP幅では「(リニューアル前後)」の直前で改行を入れたタイトルにします。タイトルテキストは ECharts でも \n で改行できます。

スマホ幅でタイトルを2行にしているのは、横幅の狭い画面で1行に収まらないからです。改行位置を明示的にコントロールしておくと、長いタイトルが画面外にはみ出すのを防げます。

optionContact も同じ構造で、data と title.text をお問い合わせページ用のものに差し替えただけです。

3)showChart と addEventListener:ボタン操作で表示・切り替える

let myChart = null;

function showChart(optionToSet, activeBtn) {
  if (!myChart) {
    myChart = echarts.init(chartDom);
  }
  myChart.setOption(optionToSet, true);

  [btnService, btnContact].forEach(btn => btn.classList.remove('is-active'));
  activeBtn.classList.add('is-active');
}

btnService.addEventListener('click', () => showChart(optionService, btnService));
btnContact.addEventListener('click', () => showChart(optionContact, btnContact));

ボタンが押されたときに、対応するグラフを表示する処理です。先に「ボタンを押すとどう動くか」を addEventListener で押さえてから、呼ばれる側の showChart の中身を見ていきます。

addEventListener

btnService.addEventListener('click', () => showChart(optionService, btnService));
btnContact.addEventListener('click', () => showChart(optionContact, btnContact));

2つのボタンそれぞれに click イベントを紐づけて、押されたら showChart に対応する option とボタン要素を渡しています。showChart の中身は次で見ます。

showChart

function showChart(optionToSet, activeBtn) {
  if (!myChart) {
    myChart = echarts.init(chartDom);
  }
  myChart.setOption(optionToSet, true);

  [btnService, btnContact].forEach(btn => btn.classList.remove('is-active'));
  activeBtn.classList.add('is-active');
}

グラフを描画して、押されたボタンをアクティブ状態にする関数です。グラフの描画には、EChartsの次の2つの関数を使います。

関数役割
echarts.init(domElement)チャートを操作するための「チャートインスタンス」を作ってHTML要素に紐づける
setOption(option)チャートインスタンスにグラフの設定を渡して実際に描画する

まず echarts.init(chartDom) でコンテナにチャートインスタンスを作ります。myChart は関数の外で確保しておき、if (!myChart) で初回のみ初期化します(二重初期化の防止)。

次に myChart.setOption(optionToSet, true) で設定を反映します。第2引数の true は「前の設定を残さず完全に置き換える」意味で、ページ切り替え時の混在を防ぎます。

最後に forEachclassList で、押されたボタンだけに is-active を付け直します。

4)resize:画面サイズに追従する

画面サイズが変わったとき(ブラウザの幅を変えたり、端末を回転させたり)に、EChartsに再描画させます。

window.addEventListener('resize', () => {
  if (myChart) myChart.resize();
});

myChart.resize() を呼ぶと、EChartsはコンテナの新しいサイズを取り直して、media クエリも再評価して、レイアウトを更新してくれます。if (myChart) のチェックは「まだボタンを押していない(=グラフが描画されていない)状態」で resize が走ったときに、null に対して .resize() を呼ばないようにするための保険です。

まとめ

この記事では、Apache EChartsを使ってレーダーチャートを実装し、デザイン調整・レスポンシブ対応・ボタン切り替え・複数系列の重ね比較まで一通り解説しました。

ポイントは下記です。

  • レーダーチャートは series.type: 'radar' で描画する。系列の色は option レベルの color 配列で一括指定する
  • 軸の項目と最大値は radar.indicator で定義する。スマホで項目名が長くてはみ出す場合は、name 内に \n を入れて2行表示にできる
  • 複数系列を重ねるには series.data に複数のオブジェクトを並べる。重なり順は配列の順で決まる(先=下、後=上)
  • media は同じ画面幅にマッチするルールを複数置けて、後ろに書いたものが優先されつつ個別プロパティでマージされる。共通設定とページ固有の上書きを分けて書けて便利

レーダーチャートは多軸の複数項目で比較するときに向いた表現です。今回のコードはデータや評価項目を差し替えるだけで、UX/UI評価以外にも商品比較・アンケート結果・能力評価・パフォーマンスベンチマークなどにそのまま使えます。ぜひご自分の案件に合わせてカスタマイズしてみてください。

押していただけると励みになります!

ABOUT ME
みなと
みなと
フロントエンドエンジニア
東京のWeb制作会社で15年以上働いている現役フロントエンドエンジニアです。これまで、いろんなプロジェクトに関わりながら、フロントエンド開発やWebデザインに取り組んできました。このブログでは、今までの経験を活かして、Web制作に役立つ情報やノウハウをシェアしていきたいと思います。初心者の方から、現場で働く方まで、誰でも参考にできる内容をお届けしますので、ぜひ覗いてみてください。
記事URLをコピーしました