この記事は、名前は聞いたことあるけど使ったことないやつをせっかくだから使ってみる Advent Calendar 2020 25日目(最終日) です。
はじめに
準備
- ここがまあ、いろいろあるわけですが
- 公式のInstallationに従ってください
- Elixir 1.6 or later(2020/12/24現在の最新は1.11)
- Erlang 20 or later(2020/12/24現在の最新は23)
- phx_new
- node.js
- PostgreSQL
- Phoenix assumes that our PostgreSQL database will have a postgres user account with the correct permissions and a password of "postgres".
- inotify-tools (for linux users)
- リンクも豊富に貼ってありますので、思い切って僕の胸に飛び込んで来てほしい
- Elixirのインストールは、手前味噌ですがインストールなどをご参照ください
うまくいかなかったら
- 何事にも準備が肝心です
- ここが一番つまらないし、謎にハマってしまうことが多いのですが、がんばってください!
- うまくいかなかったら、思い切って僕の胸に飛び込んで来てほしい (by 長嶋茂雄 読売ジャイアンツ終身名誉監督)
-
elixirjp.slack.com slack workspaceかNervesJP workspaceに入ってきていただいて、
@torifukukaiou
へご質問ください - たとえ私が答えられなくても、マジみんな親切で優しい人が多いので、きっと解決できるでしょう
-
elixirjp.slack.com slack workspaceかNervesJP workspaceに入ってきていただいて、
mix phx.new
$ mix phx.new nerves_jp_chart --live
$ cd nerves_jp_chart
$ mix setup
$ mix phx.server
- こんなのがブラウザに表示されましたでしょうか
- もし表示されない場合はなにかしら不足している等でエラーがでているとおもいますので、エラーをひとつひとつ根気よく丁寧につぶしてください
- ここを確実にしておかないと、楽しめないですよ!
ソースコードを書く
この記事は2020年12月24日に書いたものです。その後の見直しはしていません。ソースコードではChart.js 2.9.4を使っています。その当時もバージョン3は合ったような気がしますが、イゴくことを優先してまた執筆当時事例が多かった2系を使いました。Phoenixのバージョンが古いです。とりあえず動いてはいますが、Elixirで書いたプログラムをはじめいろいろなところが穴だらけです。更新したいとはおもっています(あくまでも、おもっています)。
Chart.jsの注意点については、@mnishiguchiさんがコメントを寄せてくれました。
参考にしてください。
完成品
-
NervesJP/nerves_jp_chart
-
git diff 8b19624..
の差分を全部取り込めば同じものができあがります
-
- これだと乱暴がすぎるので、
- サンプルのグラフうねうねが動くところまでいっしょにやってみましょうかね
defmodule NervesJpChartWeb.ChartSampleLive do
use NervesJpChartWeb, :live_view
def mount(_params, _session, socket) do
:timer.send_interval(1_000, self(), :next_values)
socket = assign(socket, values: Jason.encode!([]), users: Jason.encode!([]), cnt: 0)
{:ok, socket}
end
def handle_info(:next_values, socket) do
new_cnt = socket.assigns.cnt + 1
new_cnt = min(100, new_cnt)
values = 1..new_cnt |> Enum.map(fn _ -> :random.uniform() end)
users = 1..new_cnt |> Enum.map(&"user#{&1}")
{:noreply,
assign(socket,
values: Jason.encode!(values),
users: Jason.encode!(users),
cnt: new_cnt
)}
end
def render(assigns) do
~L"""
<div id="data" data-values="<%= @values %>" data-users="<%= @users %>">
<div phx-update="ignore">
<canvas id="myChart" phx-hook="chart" width="200" height="200"></canvas>
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@latest/dist/chartjs-plugin-streaming.min.js"></script>
<pre><%= @values %></pre>
"""
end
end
scope "/", NervesJpChartWeb do
pipe_through :browser
live "/", PageLive, :index
live "/chart-sample", ChartSampleLive # add
end
/* add start */
let hooks = {}
hooks.chart = {
mounted() {
let colors = [
'rgb(128, 128, 0)',
'rgb(255, 255, 0)',
'rgb(255, 0, 255)',
'rgb(192, 192, 192)',
'rgb(0, 255, 255)',
'rgb(0, 255, 0)',
'rgb(255, 0, 0)',
'rgb(128, 128, 128)',
'rgb(0, 0, 255)',
'rgb(0, 128, 0)',
'rgb(128, 0, 128)',
'rgb(0, 0, 0)',
'rgb(0, 0, 128)',
'rgb(0, 128, 128)',
'rgb(128, 0, 0)',
]
var ctx = this.el.getContext('2d');
new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
datasets: []
},
// Configuration options go here
options: {
scales: {
xAxes: [{
type: 'realtime',
realtime: {
delay: 2000,
onRefresh: function(chart) {
let len_datasets = chart.data.datasets.length;
let dataEl = document.querySelector('#data');
let len_users = JSON.parse(dataEl.dataset.users).length;
for (let i = 0; i < (len_users - len_datasets); i++) {
chart.data.datasets.push({borderColor: colors[Math.floor(Math.random() * colors.length)], data: []})
}
chart.data.datasets.forEach(function(dataset, index) {
dataset.label = JSON.parse(dataEl.dataset.users)[index]
dataset.data.push({
x: Date.now(),
y: JSON.parse(dataEl.dataset.values)[index]
});
});
}
}
}]
}
}
});
}
}
/* add end */
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks}) /* hooks を追加 */
- この変更を加えたあとに
- visit http://localhost:4000/chart-sample or http://127.0.0.1:4000/chart-sample
- に訪れてみてください
- なかなかのうねうねが見えるのではないでしょうか
git diff 8b19624..
にはもっと多くの差分があるよ
- Yes, it is.
- 2020/12/27開催の【オンライン】豪華プレゼント付!Elixir/Nerves(ナーブス)体験ハンズオン!では、みなさまのRaspberry Piからデータを打ち上げてもらうハンズオンを行いました(もう過去形)
- その関係でいろいろありますですよ
- データ保存関係のいろいろを追加しています
- Dockerで動かすためのいろいろを追加しています
- デプロイしやすいように変更を加えています
- まあ、そんなところです
- JS側の
onRefresh
で1秒ごとのタイミングをとって描画しているのですが、もっといいPhoenix LiveViewらしい書き方があるかもしれません- $\huge{ぜひおしえてください!!!}$
$ git diff 8b19624.. --stat
.env.sample | 3 +
.gitignore | 2 +
Dockerfile | 53 +++++++++++++++++
README.md | 14 +++++
assets/js/app.js | 62 +++++++++++++++++++-
config/prod.exs | 7 ++-
config/{prod.secret.exs => releases.exs} | 6 +-
docker-compose.yml | 33 +++++++++++
elixir_buildpack.config | 2 +
entrypoint.sh | 14 +++++
lib/mix/tasks/db_all_delete.ex | 10 ++++
lib/nerves_jp_chart/accounts.ex | 25 ++++++++
lib/nerves_jp_chart/accounts/user.ex | 18 ++++++
lib/nerves_jp_chart/measurements.ex | 113 +++++++++++++++++++++++++++++++++++++
lib/nerves_jp_chart/measurements/value.ex | 20 +++++++
lib/nerves_jp_chart/release.ex | 24 ++++++++
lib/nerves_jp_chart_web/controllers/fallback_controller.ex | 24 ++++++++
lib/nerves_jp_chart_web/controllers/humidity_controller.ex | 26 +++++++++
lib/nerves_jp_chart_web/controllers/temperature_controller.ex | 26 +++++++++
lib/nerves_jp_chart_web/controllers/value_controller.ex | 46 +++++++++++++++
lib/nerves_jp_chart_web/live/chart_humidity_live.ex | 63 +++++++++++++++++++++
lib/nerves_jp_chart_web/live/chart_live.ex | 54 ++++++++++++++++++
lib/nerves_jp_chart_web/live/chart_sample_live.ex | 37 ++++++++++++
lib/nerves_jp_chart_web/live/chart_temperature_live.ex | 63 +++++++++++++++++++++
lib/nerves_jp_chart_web/router.ex | 8 +++
lib/nerves_jp_chart_web/templates/layout/root.html.leex | 3 +
lib/nerves_jp_chart_web/views/changeset_view.ex | 19 +++++++
lib/nerves_jp_chart_web/views/humidity_view.ex | 12 ++++
lib/nerves_jp_chart_web/views/temperature_view.ex | 12 ++++
lib/nerves_jp_chart_web/views/value_view.ex | 16 ++++++
phoenix_static_buildpack.config | 1 +
priv/repo/migrations/20201106233307_create_users.exs | 13 +++++
priv/repo/migrations/20201106234127_create_values.exs | 14 +++++
priv/repo/migrations/20201111115618_add_kind_time_to_values.exs | 12 ++++
test/nerves_jp_chart/measurements_test.exs | 70 +++++++++++++++++++++++
test/nerves_jp_chart_web/controllers/value_controller_test.exs | 42 ++++++++++++++
36 files changed, 962 insertions(+), 5 deletions(-)
Wrapping Up
- この25日間を通して以下のものにはじめて触れたり、理解が進んだりしました
- Azure
- 工作(I2Cとか)
- GrovePi+ Starter Kit for Raspberry Pi A+,B,B+&2,3,4 (CE certified) 〜Nervesならできるもん!〜
- Nervesならできるもん! |> 本当にできんのか! (Elixir)
- Seeed株式会社様の製品を使うことで**不器用ですから**な私でもはめ込み式で手軽に電子工作を楽しめます!!!
- $\huge{Thanks!!!}$
- CircleCI
- Docker
- $\huge{Qiitaの記事中で文字に色をつけたり、でっかくしたりできるようになった}$
<font color="purple">$\huge{Qiitaの記事中で文字に色をつけたり、でっかくしたりできるようになった}$</font>
- みなさんのカレンダーはどんなですか? ぜひログインした状態でここを開いて振り返ってみてください
- Enjoy Elixir
ありがとう! Qiita Advent Calendar 2020
$\huge{毎日が12月だったらいいのに!}$
ありがとナイス! Qiita Advent Calendar 2020
$\huge{毎日が12月だったらいいのに!}$
れっつじょいなす(Let's join us)
NervesJP Slackへの参加URL