Vega1 の timer イベントを使って視覚的に残り時間がわかるタイマーを作ります。
まずは、完成系のイメージです。色分けされたドーナツグラフが時間と共に欠けていきます。
ステップ1 ドーナツグラフを表示する
今回のサンプルではタイマーの時間を30分とし、15分、25分の区切りで色を変えるようにします。
pie
transform を利用し、360度(0~2π)を 15対10対5の割合になる角度へと変換します。
"data": [
{
"name": "table",
"values": [
{"id": 1, "value": 15},
{"id": 2, "value": 10},
{"id": 3, "value": 5}
],
"transform": [
{
"type": "pie",
"field": "value",
"startAngle": 0,
"endAngle": 6.29,
"sort": false
}
]
}
],
先ほど変換した角度が入ったデータを使ってドーナツグラフを描画します。
"marks": [
{
"type": "arc",
"from": {"data": "table"},
"encode": {
"enter": {
"fill": {"scale": "color", "field": "id"},
"x": {"signal": "width / 2"},
"y": {"signal": "height / 2"}
},
"update": {
"startAngle": {"field": "startAngle"},
"endAngle": {"field": "endAngle"},
"padAngle": {"value": 0},
"innerRadius": {"signal": "innerRadius"},
"outerRadius": {"signal": "width / 2 "},
"cornerRadius": {"value": 0}
}
}
},
ステップ2 timerイベントを追加する
以下のsignal を追加します
- minutes: 計測するタイマーを指定します
{"name": "minutes", "init": "30"}
- startDate: 開いた時の時刻記録しておきます
{"name": "startDate", "init": "now()"}
- endDate: 終了時刻を記録しておきます
{"name": "endDate", "init": "now()+minutes*60*1000"}
- timer : 1秒ごとにイベントを発生させ、
経過時間/タイマー時間 × 2π
することで、どこまで進んだかの角度を計算します{ "name": "timer", "init": "0", "on": [ { "events": {"type": "timer", "throttle": 1000}, "update": "(now()- startDate)/(endDate-startDate)*6.29" } ] }
OnlineエディタのSignal Viewer でtimerが進んでいくのが確認できます。
ステップ3 ドーナツグラフを消していく
元のドーナツグラフに対して、白いドーナツグラフを重ねることでドーナツグラフを消していきます。
白いドーナツグラフを追加し、endAngle
を先ほどの timer
シグナルを設定することで、時間の経過と共に白いドーナツグラフが大きくなり、元のドーナツグラフが欠けていきます
ステップ4 文字列を表示する
最後に色の変わり目に残り時間を表示させます。
残り時間を計算するために、window
transformを利用し積み上げデータを計算します。
{
"type": "window",
"ops": ["sum"],
"fields": ["value"],
"as": ["sum"]
}
以下のようにデータ変換されます。
{"id": 1, "value": 15}, ==> {"id": 1, "value": 15, "sum": 15},
{"id": 2, "value": 10}, ==> {"id": 2, "value": 10, "sum": 25},
{"id": 3, "value": 5} ==> {"id": 3, "value": 5, "sum": 30}
経過時間から残り時間を計算し出力します。
ついでに、円と文字が被らないように半径などの微調整します。また、時間が経過すると文字を小さくしたりします。
{
"type": "text",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"signal": "width / 2"},
"y": {"signal": "height / 2"},
"radius": {"signal": "width / 2 - fontSize/2"},
"theta": {"signal": "datum.endAngle"},
"fill": {"value": "#000"},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"text": {"signal": "(minutes - datum.sum) == 0 ? minutes : (minutes - datum.sum)"}
},
"update": {
"fontSize": {"signal": "timer < datum.endAngle ? fontSize: fontSize/2"}
}
}
}
参考
過去のVega解説記事は以下です。
- Vega解説 〜離散データ〜
- Vega解説 〜動的なグラフ〜
- Vega 解説 ~時系列データを処理する~
- Vega解説 〜凡例〜
- Vega解説 〜基準線をひく〜
- Vega解説 〜複数グラフ〜
- Vega解説 ~全体グラフと詳細グラフ~
- Vega解説 〜Reactアプリ上でVegaグラフを表示し、グラフのイベントを捕まえる〜
-
Vega はjsonでデータや描画の設定を記述することで、視覚化できるツール。いろんなグラフを表現できます。 ↩