Chart.js in Elixir/Phoenix with Filtering

I was assigned to do the dashboard for this web application project were doing at my current job, and because it’s the dashboard, of course, you have charts. Considering that it’s just been months since I started doing backend stuff, I was quite pumped and curious on how to implement it on Elixir Phoenix (newbie alert 😂).

What we need:

Chart.js: You can install it using npm or bower here or use this cdnjs

https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js

Applying Chart.js

We will be using the Line Chart in this example, it’s quite easy to apply.

<canvas id="lineChart" width="400" height="400"></canvas>
var ctx = document.getElementById("lineChart").getContext('2d');var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
label: "Total # of Inquiries",
backgroundColor: "rgba(155, 89, 182,0.2)",
borderColor: "rgba(142, 68, 173,1.0)",
pointBackgroundColor: "rgba(142, 68, 173,1.0)",
data: [inquiry_jan, inquiry_feb, inquiry_mar, inquiry_apr, inquiry_may, inquiry_jun, inquiry_jul, inquiry_aug, inquiry_sep, inquiry_oct, inquiry_nov, inquiry_dec]
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});

Getting the data

Now that we have a chart, let’s start getting the data, and since we have a filter by year, let’s take care of that first.

<%= form_for @conn, dashboard_path(@conn, :dashboard), [class: "ui action input", method: "get", as: "query"], fn f -> %>     <%= select f, :year, ["2017", "2018", "2019", "2020", "2021", "2022", "2023"], class: "ui search dropdown compact", onchange: "this.form.submit();" %><% end %>
def dashboard(conn, params) do query = params["query"] || %{"year" => "2018"}
inquiries_per_month = InquiryContext.get_inquiries_per_month(query)
conn
|> render(
"dashboard.html",
inquiries_per_month: inquiries_per_month
)
end
def get_inquiries_per_month(params) do 

year = Decimal.new(params["year"])
|> Decimal.to_float
query = Repo.all from m in Inquiry,
where: fragment("date_part('year', ?)", m.inserted_at) == ^year,
group_by: fragment("month"),
select: %{
month: fragment("to_char(?, 'Mon') as month", m.inserted_at),
count: count(m.id)
}
end
the result from the query

Mapping the data

We have the data, we just need to map them to our chart, and to do that we need poison.

<script type="text/javascript">     window.inquiries_per_month = <%= raw(Poison.encode!   (@inquiries_per_month)) %></script>
var inquiry_jan = 0
var inquiry_feb = 0
var inquiry_mar = 0
var inquiry_apr = 0
var inquiry_may = 0
var inquiry_jun = 0
var inquiry_jul = 0
var inquiry_aug = 0
var inquiry_sep = 0
var inquiry_oct = 0
var inquiry_nov = 0
var inquiry_dec = 0
_.map(inquiries_per_month, (i) =>{ switch(i.month){
case "Jan":
inquiry_jan = inquiry_jan + i.count
break
case "Feb":
inquiry_feb = inquiry_feb + i.count
break
case "Mar":
inquiry_mar = inquiry_mar + i.count
break
case "Apr":
inquiry_apr = inquiry_apr + i.count
break
case "May":
inquiry_may = inquiry_may + i.count
break
case "Jun":
inquiry_jun = inquiry_jun + i.count
break
case "Jul":
inquiry_jul = inquiry_jul + i.count
break
case "Aug":
inquiry_aug = inquiry_aug + i.count
break
case "Sep":
inquiry_sep = inquiry_sep + i.count
break
case "Oct":
inquiry_oct = inquiry_oct + i.count
break
case "Nov":
inquiry_nov = inquiry_nov + i.count
break
case "Dec":
inquiry_dec = inquiry_dec + i.count
break
default:
console.log('no inquiries')

}
})
datasets: [
{
label: "Total # of Inquiries",
backgroundColor: "rgba(155, 89, 182,0.2)",
borderColor: "rgba(142, 68, 173,1.0)",
pointBackgroundColor: "rgba(142, 68, 173,1.0)",
data: [inquiry_jan, inquiry_feb, inquiry_mar, inquiry_apr, inquiry_may, inquiry_jun, inquiry_jul, inquiry_aug, inquiry_sep, inquiry_oct, inquiry_nov, inquiry_dec]
}
]

result: