ネットソリューション

SVGタグで円グラフを描画する

こんにちは。ネットソリューション事業部の山下です。
今回は、HTMLのsvgタグを使って、外部プラグインに依存せずに簡単な円グラフを作成する方法を解説します。
svgを活用することで、CSSでの色指定やアニメーション、サイズ調整が柔軟に行えるため、シンプルな円グラフに最適な手法です。

SVGで円グラフのベースを配置する

今回は400pxのsvg内に半径200pxの円を描画します。
viewBox=“0 0 width height”を設定することで、レスポンシブ対応が可能になります。
cxcyは円の中心点、rは半径を指定します。

cssではサイズの設定と始点を上に持っていくためにtransform: rotate(-90deg)を設定しています。
また、今回は円(circle)のstrokeを使用して描画していくため、塗り(fill)はnoneに設定しています。

<div class="circle-wrapper">
  <svg class="circle" viewBox="0 0 400 400" preserveAspectRatio="xMidYMid meet">
    <circle class="circle__04" cx="200" cy="200" r="200"></circle>
    <circle class="circle__03" cx="200" cy="200" r="200"></circle>
    <circle class="circle__02" cx="200" cy="200" r="200"></circle>
    <circle class="circle__01" cx="200" cy="200" r="200"></circle>
    <circle class="circle__center" cx="200" cy="200" r="100"></circle>
  </svg>
</div>

<style>
  .circle-wrapper {
    width: calc(100% - 40px);
    max-width: 400px;
    aspect-ratio: 1 / 1;
    margin-inline: auto;
  }
  .circle {
    width: 100%;
    height: 100%;
    overflow: hidden;
    border-radius: 100%;
  }

  circle {
    fill: none;
    transform: rotate(-90deg);
    stroke-width: 100%;
    transform-origin: center center;
    stroke: #000;
  }

  .circle__center {
    fill: #fff;
    stroke-width: 0;
  }
</style>

解説

preserveAspectRatioは要素がどのように表示領域に収まるかを制御する属性です。
次の形式で指定します。

preserveAspectRatio="<align> <meetOrSlice>"

alignのオプション

  • xMinYMin: 左上に配置
  • xMidYMin: 水平中央、垂直上
  • xMaxYMin: 右上
  • xMinYMid: 左中央
  • xMidYMid: 中央
  • xMaxYMid: 右中央
  • xMinYMax: 左下
  • xMidYMax: 水平中央、垂直下
  • xMaxYMax: 右下

meet

コンテンツのアスペクト比を保持しながら、表示領域全体に収まるように縮小または拡大します。
background-size: containのような動きをします。

slide

表示領域全体を埋めるように縮小または拡大しますが、余剰部分は切り取られます。
background-size: coverのような動きをします。

stroke-dasharrayとstroke-dashoffsetを設定する

stroke-dasharraystroke-dashoffsetに円周の長さの値を設定します。
円周の長さは次のように計算できます。

円周 = 2 * π * 半径

これをcss上で計算する場合、例えば、半径が200pxの場合

stroke-dasharray: calc(2 * 3.14159 * 200);
stroke-dashoffset: calc(2 * 3.14159 * 200);

stroke-dasharray

  • 値のペアとして、線の長さ (dash-length) とその後の空白 (gap-length) を指定します。
  • 値を1つだけ指定した場合、それが線の長さとみなされ、空白は自動で同じ長さになります。
  • 連続したパターンを指定することで、点線や破線を作ることができます。

stroke-dashoffset

  • 線の開始位置をずらすためのプロパティです。
  • 値は線の描き始めをどれだけずらすかを指定します。
  • 正の値で線を逆時計回りに「消す」方向へ、負の値で時計回りに「増やす」方向へ動かせます。

これらのプロパティを同時に設定すると、円周分の線を描画した後、その線を円周分だけずらすことができます。その結果、線がすべて表示されていない状態になります。

ちなみに、この設定を適用したSVGを下記に配置していますが……
現時点ではもちろん表示されていないですね。

ためしに1つだけ、stroke-dashoffsetを変更して表示してみます。

表示されましたね!
いかがだったでしょうか。このように……

……さすがにこのままでは終われないので続きを解説をしていきます。
今回は25%の領域を表示してみました。
cssではこのようにstroke-dashoffsetを設定します。

stroke-dashoffset: calc((2 * 3.14159 * 200) * (1 - 0.25));

同じようにして、すべての領域を表示してみましょう。ここで重要なポイントがあります。
すべての円グラフの開始点は常にグラフの上から始まるということです。
最初のグラフは25%(0.25)で描画できますが、それ以降のグラフは、前のグラフの描画済み部分(例えば、0.25分)を計算に入れてから描画しなければなりません。

描画順序の重要性

  • SVGタグの描画順序は、最初に記述された要素から順に行われます。
  • 次の要素は前の要素の上に描画され、重なります。

このため、描画の順番としては次のようになります:

  1. 青のグラフを100%で描画。
  2. その上に、黄色のグラフを55%描画(青のグラフの上に重なる)。
  3. 次に、緑のグラフを35%描画(黄色の上に重なる)。
  4. 最後に、赤のグラフを25%描画(緑の上に重なる)。
/* 赤のグラフ25% */
.circle__01--03 {
  stroke-dashoffset: calc((2 * 3.14159 * 200) * (1 - 0.25));
}

/* 緑のグラフ20% */
.circle__02--03 {
  stroke-dashoffset: calc((2 * 3.14159 * 200) * (1 - 0.25 - 0.2));
}

/* 黄のグラフ10% */
.circle__03--03 {
  stroke-dashoffset: calc((2 * 3.14159 * 200) * (1 - 0.25 - 0.2 - 0.1));
}

/* 青のグラフ 一番下なので100%描画 */
.circle__04--03 {
  stroke-dashoffset: calc((2 * 3.14159 * 200) * (1 - 1));
}

アニメーションを追加する

さて、冒頭でお話ししたようにこれらはcssでプロパティを設定することができますので、tranisiton,animationも追加することができます。
※ただし、calc()はアニメーションのキーフレーム内では動的に計算されないため、あらかじめ計算結果を数値として指定する必要があることにご注意ください。
(scss側でコンパイル時に計算した結果を出力、とかだと大丈夫なのかな・・?)

マウスオン!

いかがだったでしょうか。
svgを活用することで、簡単な円グラフであればプラグイン無しで対応することができました。
今回の記事がどこかの誰かのお悩みを解決する一歩になれば幸いです。
それではまた次回。

しかし、今回のグラフの配色……ChatGPT君に決めてもらったんですがやたらGoogleアイコンっぽいな……?

Webの進化の速さにアップアップですがなんとか喰らいついていきたい。

山下 X@Frencel_ns

フロントエンドエンジニア
フレームワーク頑張りたい人
モンハンワイルズではキアヌ・リーブス似のイケオジでプレイしたい

好きなモンスターハンターの武器

双剣・狩猟笛

mail お問い合わせ

ご覧いただきありがとうございます。
当メディアへのご質問や各事業部へのお仕事のご相談がありましたら、お気軽にお問い合わせください。

article 過去記事