こんにちは、あんこ先生です。
ギャラリーで棒グラフを表現した次ステップとして、折れ線グラフも作りたくありませんか?
とはいえ、PowerAppsには自由な角度で線を引く機能が備わっていません。
その問題を解決するために、自由に線や円などを描画できるSVGにがんばってもらいます。
今回は「きれいな折れ線グラフを作りたい」という要望にお応えするため、SVGとギャラリーを使った折れ線グラフを作る方法を紹介します。
もちろん、別記事で紹介しているラベル表示やタイムラインにも対応できます。
この記事を読めば、素敵な折れ線グラフが作成できるようになります。
なお、今回も下記記事で紹介した棒グラフを基に、機能を追加する形で解説しています。
SVGとギャラリーで折れ線グラフを作る方法
以前、別記事でSVGだけで折れ線グラフを作る方法を消化しました。
この方法でもさほど問題はないのですが、ラベル表記ができない、ギャラリーのSelectedが利用できないという問題がありました。
今回はそこを解消するため、ギャラリーのテンプレートにSVGを埋め込む方法で対応します。
折れ線グラフのサンプルデータを作成する
折れ線グラフを作るためには、棒グラフ同様、x軸とy軸の二次元データが必要です。
別記事ではランダムな値で構成された10レコード分のコレクションを作成しました。
今回も、下記コードを使ってランダムな値で構成された10レコード分のコレクションを作成します。
コレクションの中身は変わらず、連番、x軸の日付、y軸の値の3項目で構成されます。
Clear(_GraphData);
ForAll(Sequence(10,1),
Collect(_GraphData,
{
連番:Value,
日付:Today()+Value,
値:RoundUp(Rand()*30+20,0)
}
)
);
折れ線グラフの描画領域を追加する
冒頭でも述べましたが、棒グラフと追従するラベルの作成方法は別記事で紹介しています。
これを流用するなら、ギャラリーのテンプレートに画像をひとつ追加するだけで済みます。
サイズは50*250で、座標は日付を表示しているLabelDateの上面に乗せるよう配置します。
SVGで折れ線グラフを描画する
接点を表示させる
始めに、線と線が交わる接点を円で表示させます。
求め方は棒グラフのYと同じです。
画像の高さ(Self.Height)から値×重みで算出できます。
重みを大きくすると描画領域から外れ見えなくなります。
小さくすると要素間の差が分かりにくくなるので、適切な値を設定しましょう。
なお、高さは250、サンプルデータの値上限が50なので、少し余裕を持たせて重みを4.5に設定しています。
それでは、下記コードを画像のImageプロパティに記述してください。
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
隣接する接点を繋げる│次の要素へ
折れ線部分は、接点を基準に2本表示させます。
なぜなら、SVGは描画領域をこえて線などを表示できないからです。
線を繋げるには、隣の画像から線を伸ばす必要があります。
連番列がある前提ですが、隣接する値を参照するには、次の2通りがあります。
- LastやFirstN関数などで指定する。
- LookUp関数で指定する。
好みで使い分けてください。
コード例は次の通りです。
(Last(FirstN(_GraphData,ThisItem.連番+1)).値
LookUp(_GraphData,連番=ThisItem.連番+1,ThisRecord.値)
そのため、まずは次の接点への線を表示させます。
隣の画像からも線を伸ばすため、終点は要素間の差を2で割った分だけずらします。
では、下記コードを画像のImageプロパティに記述してください。
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='50'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番+1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
隣接する接点を繋げる│前の要素へ
次に、ひとつ前の接点への線を表示させます。
おなじように終点は要素間の差を2で割った分だけずらします。
では、下記コードを画像のImageプロパティに記述してください。
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='0'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番-1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
最初と最後の線を非表示にする
図のように、前後いずれかの値がない最初と最後のレコードで不要な線が表示されています。
これは、If文でSVGの描画をコントロールし、非表示とさせます。
具体的には、最初のレコードなら前の線を描かない、最後のレコードなら後ろの線を描かない、といった形です。
コレクションに連番をつけているので、判定は容易です。
それらに対応した下記コードを画像のImageプロパティに記述してください。
If(First(_GraphData).連番=ThisItem.連番,
//最初のレコード
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='50'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番+1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
,
Last(_GraphData).連番=ThisItem.連番,
//最後のレコード
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='0'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番-1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
,
//それ以外
"data:image/svg+xml,"
&EncodeUrl("
<svg viewBox='0 0 "&Self.Width&" "&Self.Height&"' xmlns='http://www.w3.org/2000/svg'>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='0'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番-1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<line
x1='25'
y1='"&Self.Height-ThisItem.値*4.5&"'
x2='50'
y2='"&Self.Height-ThisItem.値*4.5-(Last(FirstN(_GraphData,ThisItem.連番+1)).値*4.5-ThisItem.値*4.5)/2&"'
stroke='RGBA(246, 88, 16, 1)'
/>
<circle
cx='25'
cy='"&Self.Height-ThisItem.値*4.5&"'
r='5'
fill='RGBA(255,0,0,1)'
/>
</svg>")
)
ラベルを表示させる
棒グラフと同様に選択した値をラベルに表示させる場合は、画像のOnSelectに次のコードを記述してください。
If(_press=ThisItem.連番,
Reset(TimerVis);Set(_press,0);,
Reset(TimerVis);Set(_press,0);Set(_press,ThisItem.連番)
)
SVGとギャラリーを使った折れ線グラフのまとめ
今回はSVGとギャラリーを使って折れ線グラフを作る方法を紹介しました。
SVGを使った描画と、前後のレコードから値を比較させる方法が学べたと思います。
棒グラフの値を降順に並び替え、折れ線グラフの値を累積にすればパレート図も作れますね。
別記事で紹介しているラベル表示もそのまま使えますし、タイムラインにも対応できます。
あえてPowerAppsで表現することにこだわって、集計・分析アプリを作成してみましょう!
コメントを残す