MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

Power Apps で SVGを利用したレーダーチャートコンポーネントの作成

Twitterで『Power Apps Communityのサンプルでレーダーチャートがある』という呟きを拝見したのがきっかけです。

powerusers.microsoft.com

ただしこちらのコンポーネント、8角形と5角形のみで値も5段階のみということでした。

よく見る3角形のレーダーチャートとか、10段階のチャートとかも使えないようでしたので、一般化してみました。

3以上のN角形で、M段階のレーダーチャートを作成できます。

もちろん値の表示も可能です。

f:id:mofumofu_dance:20220215213442p:plain

ということで、今回はSVGのレーダーチャートをどうやって作ったかを紹介します。

サンプルのダウンロードは以下からどうぞ

github.com

SVG で多角形を描く

SVGで多角形を描くときには、<polygon ~/>という要素を使います。polygonでは多角形の各頂点のXY座標を指定します。

四角形を描くときには4つのXYペアを指定します。

f:id:mofumofu_dance:20220215214139p:plain

"data:image/svg+xml,"& EncodeUrl(
    "<svg viewBox='-110,-110,220,220' xmlns='http://www.w3.org/2000/svg'>"
    &"<polygon points='100,-100 -100,-100 -100,100 100,100' stroke-width='1' stroke='darkgray' fill='none'/>"//多角形はpolygon要素で頂点のXY座標を指定
    &"</svg>"
  )

XYペアを任意の個数指定すれば、N角形を描くことができますね。

たいていの場合、Power Appsで特定の規則に従った数字の組 を作るときには Sequence()関数を使うことでスッキリ書けます。(一般のN角形とかにもすぐ適用できる)

任意の多角形N を描くのであれば、Sequence()Concat()関数を組み合わせて

Concat(Sequence(N),100*Cos(2*Pi()*Value/N)&","&100*Sin(2*Pi()*Value/N)," ")

これでN角形の各頂点座標を生成できます。例えば5角形であれば上の式にN=5を設定するとX,Yの組が5つ生成されます。

f:id:mofumofu_dance:20220215215113p:plain

これを使って、polygonの座標を指定します。Power Apps上では以下のように書けます。

"data:image/svg+xml,"& EncodeUrl(
    "<svg viewBox='-110,-110,220,220' xmlns='http://www.w3.org/2000/svg'>"
    &"<polygon points='"&Concat(Sequence(N),100*Cos(2*Pi()*Value/N)&","&100*Sin(2*Pi()*Value/N)," ")&"' stroke-width='1' stroke='darkgray' fill='none'/>"//多角形はpolygon要素で頂点のXY座標を指定
    &"</svg>"
  )

f:id:mofumofu_dance:20220215214813p:plain

ここで、100*Cos(...100は図形の大きさを表します。これを大きくしたり小さくすれば、大きい/小さい多角形も書くことができます。

複数の多角形を一緒に描く

レーダーチャートの目盛り部分は複数の大きさの正N角形を組み合わせてできています。例えば大きさ100の5角形と大きさ50の5角形を重ねて書きたい場合には

"data:image/svg+xml,"& EncodeUrl(
    "<svg viewBox='-110,-110,220,220' xmlns='http://www.w3.org/2000/svg'>"
    &"<polygon points='"&Concat(Sequence(N),100*Cos(2*Pi()*Value/N)&","&100*Sin(2*Pi()*Value/N)," ")&"' stroke-width='1' stroke='darkgray' fill='none'/>"
    &"<polygon points='"&Concat(Sequence(N),50*Cos(2*Pi()*Value/N)&","&50*Sin(2*Pi()*Value/N)," ")&"' stroke-width='1' stroke='darkgray' fill='none'/>"
    &"</svg>"
  )

polygonを2つ続けて書けばOKです。

f:id:mofumofu_dance:20220215215617p:plain

では任意の段階に分割するにはどうすればいいかというと、またSequenceとConcatを使います。

100の部分を100/M*valueみたいに、M分割すればいいわけです。

Concat(
    RenameColumns(Sequence(M),"Value","val"),
         "<polygon points='"&Concat(Sequence(N),100/M*val*Cos(2*Pi()*Value/N)&","&100/M*val*Sin(2*Pi()*Value/N)," ")&"' stroke-width='1' stroke='darkgray' fill='none'/>",
         Char(10)
)

こんな感じで、連結していきます。

N=5, M=4のケースではpolygon要素が4つ生成されます。

f:id:mofumofu_dance:20220215220315p:plain

SVGにすれば確かに4つの5角形が均等な幅で表示されます。

f:id:mofumofu_dance:20220215220413p:plain

全体の回転

上の図を見てみると、なんとなく傾いています。実際、期待する正多角形 (真ん中上に頂点がくる) からすると90度傾いています。

この傾きを補正するために、SVG全体を-90度回転させます。

これには transform='rotate(-90)'というおまじないをくっつけます。

f:id:mofumofu_dance:20220215220715p:plain

こうするとSVG全体が-90度回転してくれます。

f:id:mofumofu_dance:20220215220748p:plain

よく見る感じのレーダーチャートの基礎部分ができました。

あとは同じように、polygonを使ってデータを表示します。ここまででお気づきかもしれませんが 100 の部分をいい具合に置き換えてあげればいいわけです。

今回のコンポーネントでは[10,20,45,11,...]のようなデータを収めた数値の配列を入力していただくと、いい具合に (Last(FirstN(....))部分) レーダーチャートのデータを表す多角形を描いてくれています。

f:id:mofumofu_dance:20220215221228p:plain

おわり

ということで、サンプルをただ使うだけでもいいんですが、大体どこで何をやっているかわかっていただけたらと思い、概要をご紹介しました。

一般化する!といったときに大体はSequence関数を、文字列を生成するにはConcatを使って勝負します。何かの一般化するときの発想の種になれば幸いです。

改めて、サンプルは以下からどうぞー。

github.com