JavaScript

【SVG】簡単に円弧を描くコピペ用サンプル(正円限定)

SVG要素の左上が原点(0, 0)、X軸は右方向が正、Y軸は下方向が正

SVGの円弧を使ってHTML上でメーターのようなものを作る機会があり、その延長で簡単に円弧を描く関数を作成しました。

今回は簡単に円弧が描けるコピペ用のコード(HTML?)と、それを使ってメーターのように動く円弧を描く方法を紹介します。

SVGの円弧の簡単な描き方

サンプルコード

早速ですがサンプルコードです。

長く見えますが、9割はコピペで使えるので簡単です。
(後述の解説を見ていただければ直接描くより簡単だと分かると思います)

使用方法はコメント中に記載しています。

<!-- 描画先のSVG -->
<svg id="mySVG" style="width: 200; height: 200;">
  <!-- 描画先の<path>要素
    fill: noneを指定しておかないと円弧の内側が塗りつぶされるので注意
    stroke: 円弧の線の色
    stroke-width: 円弧の線の幅

    ※実際のパスを定義するd要素は後述のJavaScriptで描画
  -->
  <path id="myArc" fill="none" stroke="#ff0000" stroke-width="10"/>
</svg>


<script>


// ↓↓ここからコピペ↓↓

/**
 * SVGに円弧(正円)を描画する関数
 * 
 * @param {HTMLElement} svg SVGの<path>要素
 * @param {number} radius 円の半径
 * @param {number} x0 円の中心のX座標
 * @param {number} y0 円の中心のY座標
 * @param {number} startAngle 円弧の始点の角度(X軸方向を0度として度数法で指定)
 * @param {number} angle 円弧の角度(startAngleからの角度を度数法で指定)
 **/
function drawArc(svg, radius, x0, y0, startAngle, angle) {
  // 0~360度の範囲になるように補正
  if (Math.abs(angle) >= 360) {
    angle = angle % 360
  }

  // 角度をラジアンに直す
  let startRad = startAngle * Math.PI / 180
  let rad = (startAngle + angle) * Math.PI / 180

  // 円弧始点の座標
  // 極座標: x = r * cosΘ, y = - r * sinΘ
  // HTML上はY軸は↓方向なので符号注意
  let x1 = (Math.cos(startRad) * radius + x0)
  let y1 = (- Math.sin(startRad) * radius + y0)

  // 円弧の半径(正円なのでxもyも同じ)
  let rx = radius
  let ry = radius

  // x-axis-rotation(正円なので0固定)
  let start = 0

  // large-arc-flag
  // 0: 180度以内、1: 180度以上
  let f1 = 0
  if (Math.PI <= Math.abs(rad - startRad)) {
    f1 = 1
  }

  // sweep-flag
  // 0: 反時計回り、1: 時計回り
  let f2 = 0
  if (angle < 0) {
    f2 = 1
  }

  // 円弧終点の座標
  // 極座標: x = r * cosΘ, y = - r * sinΘ
  // HTML上はY軸は↓方向なので符号注意
  let x2 = x0 + (Math.cos(rad) * radius)
  let y2 = y0 + (- Math.sin(rad) * radius)

  // SVGのパス要素に反映
  svg.setAttribute('d', `M ${x1} ${y1} A ${rx} ${ry} ${start} ${f1} ${f2} ${x2} ${y2}`);
}

// ↑↑コピペここまで↑↑


// 使用例(描きたい円弧に合わせて適宜変える)
// 半径50, 円の中心(100, 100), 90度~270度の円弧(180度の円弧)を描く例
drawArc(document.getElementById("myArc"), 50, 100, 100, 90, 180)

</script>

これを実際に描画すると以下になります。

ここで注意しないといけないのは通常HTML上ではY軸の座標が下方向という点です。

上記の使用例だと以下のような位置関係になります。

SVG要素の左上が原点(0, 0)、X軸は右方向が正、Y軸は下方向が正

メーターのように動く円弧の描き方

前述の簡単に円弧を描く方法を使えば、メーターのように動く円弧も簡単に作ることができます。

例えば、1フレーム毎に1度ずつ動く円弧であれば以下のようになります。

<!-- 描画先のSVG -->
<svg id="mySVG" style="width: 200; height: 200;">
  <!-- 描画先の<path>要素
    fill: noneを指定しておかないと円弧の内側が塗りつぶされるので注意
    stroke: 円弧の線の色
    stroke-width: 円弧の線の幅

    ※実際のパスを定義するd要素はコピペ部分のJavaScriptで描画
  -->
  <path id="myArc" fill="none" stroke="#ff0000" stroke-width="10"/>
</svg>


<script>

/**
 * SVGに円弧(正円)を描画する関数
 * 
 * @param {HTMLElement} svg SVGの<path>要素
 * @param {number} radius 円の半径
 * @param {number} x0 円の中心のX座標
 * @param {number} y0 円の中心のY座標
 * @param {number} startAngle 円弧の始点の角度(X軸方向を0度として度数法で指定)
 * @param {number} angle 円弧の角度(startAngleからの角度を度数法で指定)
 **/
function drawArc(svg, radius, x0, y0, startAngle, angle) {
  // 0~360度の範囲になるように補正
  if (Math.abs(angle) >= 360) {
    angle = angle % 360
  }

  // 角度をラジアンに直す
  let startRad = startAngle * Math.PI / 180
  let rad = (startAngle + angle) * Math.PI / 180

  // 円弧始点の座標
  // 極座標: x = r * cosΘ, y = - r * sinΘ
  // HTML上はY軸は↓方向なので符号注意
  let x1 = (Math.cos(startRad) * radius + x0)
  let y1 = (- Math.sin(startRad) * radius + y0)

  // 円弧の半径(正円なのでxもyも同じ)
  let rx = radius
  let ry = radius

  // x-axis-rotation(正円なので0固定)
  let start = 0

  // large-arc-flag
  // 0: 180度以内、1: 180度以上
  let f1 = 0
  if (Math.PI <= Math.abs(rad - startRad)) {
    f1 = 1
  }

  // sweep-flag
  // 0: 反時計回り、1: 時計回り
  let f2 = 0
  if (angle < 0) {
    f2 = 1
  }

  // 円弧終点の座標
  // 極座標: x = r * cosΘ, y = - r * sinΘ
  // HTML上はY軸は↓方向なので符号注意
  let x2 = x0 + (Math.cos(rad) * radius)
  let y2 = y0 + (- Math.sin(rad) * radius)

  // SVGのパス要素に反映
  svg.setAttribute('d', `M ${x1} ${y1} A ${rx} ${ry} ${start} ${f1} ${f2} ${x2} ${y2}`);
}


// 関数の使用例(円弧が描画されるアニメーションの例)

// 各種変数の定義
let svg = document.getElementById("myArc") // SVGの<path>要素
let radius = 50 // 円の半径
let x0 = 100 // 円の中心のx座標
let y0 = 100 // 円の中心のy座標
let startAngle = 270 // 円弧始点の角度
let currentAngle = 0 // 円弧の初期角度

// アニメーションを描画する関数
function draw() {
  // 円弧描画の関数呼び出し
  drawArc(svg, radius, x0, y0, startAngle, currentAngle)
  // 円弧の角度更新(+で反時計回り、-で時計回りの円弧)
  currentAngle = currentAngle + 1
  requestAnimationFrame(draw)
}

draw()

</script>


これを実際に動かすと以下のようにメーター風の円弧が描けます。

[解説]SVGで円弧を描く方法

では最後に上記の方法が簡単な理由を見てもらうために、HTMLとSVGで円弧を描く方法を紹介します。

SVGで円弧を描画する方法はmozillaのドキュメントにもある通り、SVGの<path>要素を使って表現します。

例えば以下のように記述します。

<svg style="width: 100; height: 100;">
    <path d="M 50 50 A 20 20 0 1 0 0 50" fill="none" stroke="#ff0000" stroke-width="5"/>
</svg>

まず簡単な部分から説明します。

fillは円弧の内側を塗りつぶすかどうかを指定します。塗りつぶさない場合はnoneを指定します。
strokeは円弧の線の色を指定します。
stroke-widthは円弧の線の太さを指定します。

次が厄介な部分なのですが、d要素でパスを定義します。
円弧の構文は以下です。

 M x1 y1 A rx ry x-axis-rotation large-arc-flag sweep-flag x2 y2

M x1 y1は始点の座標を表します。

例えばM 0 0はsvg要素の左上を表します。
先ほども書きましたがHTML上ではy軸は下方向が正という点にはご注意ください。

Aから後ろは円弧の描画を表します。

rx, ryは円の半径を表します。rxとryに同じ値を指定すると正円になります。

x-axis-rotationは円自体の傾きです。正円の場合は何を指定しても同じです。

large-arc-flagは円弧が0~180か180~360なのかを指定するフラグです。
0~180の場合は0, 180~360の場合は1を指定します。

sweep-flagは円弧の描画方向を表します。
sweep-flagが0の場合は正(反時計回り)、1の場合は負(時計回り)を表します。

x2, y2は円弧の終点の座標を表します。

x1, y1, x2, y2は高校で習った円/楕円の方程式を思い出して計算すると分かり易いです。
何度でも書きますが、Y軸が下方向という点だけは注意してください。

また、円弧の描画方法の別解として、以下もあります。

M x1 y1 a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy

Aではなくaで指定することで、dx, dyつまり、x1, y1からの相対座標での指定となります。


一応これがSVGで円弧を描画する場合の構文になりますが、読んでいただいたら分かる通り、指定がかなり面倒ですね。
なので、正円限定にはなりますが、簡単に円弧を描きたい場合は冒頭で紹介した方法が便利だと思います。


今回の記事は以上となります。
今日日人間がSVG直接いじることなんて稀かもしれませんが、もし私のようにSVGの円弧でてこずった方がいれば是非ご活用いただければと思います。

参考

https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths#%E5%86%86%E5%BC%A7
http://yamatyuu.net/computer/html/svg/arc.html

コメント

タイトルとURLをコピーしました