generate statistics sparklines

This commit is contained in:
byte[] 2019-12-05 08:55:49 -05:00
parent d8e3b9e4ff
commit 6882dd00e3
5 changed files with 91 additions and 0 deletions

View file

@ -3,6 +3,7 @@ defmodule PhilomenaWeb.ProfileController do
alias PhilomenaWeb.ImageLoader
alias Philomena.Textile.Renderer
alias Philomena.UserStatistics.UserStatistic
alias Philomena.Users.User
alias Philomena.Galleries.Gallery
alias Philomena.Posts.Post
@ -82,6 +83,8 @@ defmodule PhilomenaWeb.ProfileController do
|> limit(5)
|> Repo.all()
statistics = calculate_statistics(user)
interactions =
Interactions.user_interactions([recent_uploads, recent_faves], current_user)
@ -95,7 +98,38 @@ defmodule PhilomenaWeb.ProfileController do
recent_comments: recent_comments,
recent_posts: recent_posts,
recent_galleries: recent_galleries,
statistics: statistics,
layout_class: "layout--wide"
)
end
defp calculate_statistics(user) do
now =
DateTime.utc_now()
|> DateTime.to_unix(:second)
|> div(86400)
last_90 =
UserStatistic
|> where(user_id: ^user.id)
|> where([us], us.day > ^(now - 89))
|> Repo.all()
|> Map.new(&{&1.day, &1})
%{
uploads: individual_stat(last_90, :uploads),
images_favourited: individual_stat(last_90, :images_favourited),
comments_posted: individual_stat(last_90, :comments_posted),
votes_cast: individual_stat(last_90, :votes_cast),
metadata_updates: individual_stat(last_90, :metadata_updates),
forum_posts: individual_stat(last_90, :forum_posts)
}
end
defp individual_stat(mapping, stat_name) do
Enum.map((89..0), &map_fetch(mapping[&1], stat_name) || 0)
end
defp map_fetch(nil, _field_name), do: nil
defp map_fetch(map, field_name), do: Map.get(map, field_name)
end

View file

@ -0,0 +1,28 @@
.block
.block__header: span.block__header__title Statistics
.block__content
table.table.table--stats.center
tr
td.table--stats__parameter Uploads
td.table--stats__value = number_with_delimiter(@user.uploads_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.uploads)
tr
td.table--stats__parameter Favorites
td.table--stats__value = number_with_delimiter(@user.images_favourited_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.images_favourited)
tr
td.table--stats__parameter Comments
td.table--stats__value = number_with_delimiter(@user.comments_posted_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.comments_posted)
tr
td.table--stats__parameter Votes
td.table--stats__value = number_with_delimiter(@user.votes_cast_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.votes_cast)
tr
td.table--stats__parameter Metadata Updates
td.table--stats__value = number_with_delimiter(@user.metadata_updates_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.metadata_updates)
tr
td.table--stats__parameter Forum Posts
td.table--stats__value = number_with_delimiter(@user.forum_posts_count)
td.table--stats__sparkline: .sparkline = sparkline_data(@statistics.forum_posts)

View file

@ -51,6 +51,7 @@
= pretty_time(award.awarded_on)
.column-layout__main
= render PhilomenaWeb.ProfileView, "_statistics.html", user: @user, statistics: @statistics, conn: @conn
= render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Uploads", images: @recent_uploads, view_all_path: Routes.search_path(@conn, :index, q: "uploader_id:#{@user.id}"), conn: @conn
= render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Favorites", images: @recent_faves, view_all_path: Routes.search_path(@conn, :index, q: "faved_by_id:#{@user.id}"), conn: @conn
= render PhilomenaWeb.ProfileView, "_recent_galleries.html", galleries: @recent_galleries, user: @user, conn: @conn

View file

@ -64,6 +64,7 @@ defmodule PhilomenaWeb.AppView do
Canada.Can.can?(conn.assigns.current_user, action, model)
end
def number_with_delimiter(nil), do: "0"
def number_with_delimiter(number) do
number
|> to_charlist()

View file

@ -17,6 +17,33 @@ defmodule PhilomenaWeb.ProfileView do
def award_title(award),
do: award.badge_name
def sparkline_data(data) do
# Normalize range
{min, max} = Enum.min_max(data)
max = max(max, 0)
min = max(min, 0)
content_tag :svg, [width: "100%", preserveAspectRatio: "none", viewBox: "0 0 90 20"] do
for {val, i} <- Enum.with_index(data) do
# Filter out negative values
calc = max(val, 0)
# Lerp or 0 if not present
height = zero_div((calc - min) * 20, max - min)
# In SVG coords, y grows down
y = 20 - height
content_tag :rect, [class: "barline__bar", x: i, y: y, width: 1, height: height] do
content_tag :title, val
end
end
end
end
defp zero_div(_num, 0), do: 0
defp zero_div(num, den), do: div(num, den)
defp badge_url_root do
Application.get_env(:philomena, :badge_url_root)
end