ML-200: switch to a vertical chart
This commit is contained in:
@@ -75,6 +75,77 @@ defmodule MusicLibraryWeb.ChartComponents do
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a vertical bar chart using CSS Grid.
|
||||
|
||||
Columns flow horizontally, use a fixed-height plotting area, and scroll on
|
||||
narrow screens while keeping labels and values visible.
|
||||
|
||||
## Examples
|
||||
|
||||
<.vertical_bar_chart
|
||||
data={[{"May 01", 5}, {"May 02", 3}]}
|
||||
label_fn={&elem(&1, 0)}
|
||||
value_fn={&elem(&1, 1)}
|
||||
color_class="bg-emerald-500 dark:bg-emerald-400"
|
||||
/>
|
||||
"""
|
||||
attr :data, :list, required: true
|
||||
attr :label_fn, :any, required: true
|
||||
attr :value_fn, :any, required: true
|
||||
attr :color_class, :string, required: true
|
||||
attr :class, :string, default: ""
|
||||
attr :datum_click, :any, default: nil, doc: "the function for handling phx-click on each datum"
|
||||
|
||||
def vertical_bar_chart(assigns) when assigns.data != [] do
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(:max_value, max_value(assigns.data, assigns.value_fn))
|
||||
|
||||
~H"""
|
||||
<div class={["w-full overflow-x-auto p-4", @class]}>
|
||||
<div class="grid min-w-full grid-flow-col auto-cols-[minmax(1.75rem,1fr)] items-end gap-2">
|
||||
<%= for datum <- @data do %>
|
||||
<% percentage = bar_percentage(@value_fn.(datum), @max_value) %>
|
||||
<% label = to_string(@label_fn.(datum)) %>
|
||||
|
||||
<%= if @datum_click do %>
|
||||
<div
|
||||
class="group flex h-72 cursor-pointer flex-col items-center justify-end gap-2"
|
||||
phx-click={@datum_click.(datum)}
|
||||
>
|
||||
<.vertical_bar_column
|
||||
label={label}
|
||||
percentage={percentage}
|
||||
value={@value_fn.(datum)}
|
||||
color_class={@color_class}
|
||||
grouped
|
||||
/>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="flex h-72 flex-col items-center justify-end gap-2">
|
||||
<.vertical_bar_column
|
||||
label={label}
|
||||
percentage={percentage}
|
||||
value={@value_fn.(datum)}
|
||||
color_class={@color_class}
|
||||
/>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def vertical_bar_chart(assigns) do
|
||||
~H"""
|
||||
<div class={["w-full", @class]}>
|
||||
{gettext("No data available")}
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
attr :label, :string, required: true
|
||||
attr :percentage, :float, required: true
|
||||
attr :value, :any, required: true
|
||||
@@ -110,6 +181,49 @@ defmodule MusicLibraryWeb.ChartComponents do
|
||||
"""
|
||||
end
|
||||
|
||||
attr :label, :string, required: true
|
||||
attr :percentage, :float, required: true
|
||||
attr :value, :any, required: true
|
||||
attr :color_class, :string, required: true
|
||||
attr :grouped, :boolean, default: false
|
||||
|
||||
defp vertical_bar_column(assigns) do
|
||||
~H"""
|
||||
<div class="shrink-0 text-xs font-semibold text-zinc-500 dark:text-zinc-400">
|
||||
{@value}
|
||||
</div>
|
||||
<div
|
||||
class="flex h-36 w-full shrink-0 items-end rounded bg-zinc-200 dark:bg-zinc-700"
|
||||
title={"#{@label}: #{@value}"}
|
||||
aria-label={"#{@label}: #{@value}"}
|
||||
data-chart-label={@label}
|
||||
data-chart-value={@value}
|
||||
>
|
||||
<div
|
||||
class={[
|
||||
"w-full rounded-t opacity-80 transition-opacity",
|
||||
@color_class,
|
||||
if(@grouped, do: "group-hover:opacity-100")
|
||||
]}
|
||||
style={"height: #{@percentage}%"}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative h-20 w-full shrink-0 overflow-visible">
|
||||
<div
|
||||
class={[
|
||||
"absolute top-6 left-1/2 w-16 origin-center -translate-x-1/2 -rotate-90 text-center text-xs font-medium whitespace-nowrap",
|
||||
"text-zinc-500 dark:text-zinc-400",
|
||||
if(@grouped, do: "group-hover:text-zinc-700 dark:group-hover:text-zinc-200")
|
||||
]}
|
||||
title={@label}
|
||||
>
|
||||
{@label}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp max_value(data, value_fn) do
|
||||
max = Enum.max_by(data, value_fn)
|
||||
value_fn.(max)
|
||||
|
||||
@@ -82,9 +82,9 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|
||||
<.section>
|
||||
<:title>{gettext("Daily Scrobbles")}</:title>
|
||||
<div class="mt-5 rounded-md bg-white shadow-sm dark:bg-zinc-800">
|
||||
<.horizontal_bar_chart
|
||||
<.vertical_bar_chart
|
||||
data={@daily_scrobble_counts}
|
||||
color_class="bg-emerald-500"
|
||||
color_class="bg-red-500 dark:bg-red-400"
|
||||
label_fn={fn %{date: date, count: _count} -> Calendar.strftime(date, "%b %d") end}
|
||||
value_fn={fn %{date: _date, count: count} -> count end}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user