Make charts responsive

This commit is contained in:
Claudio Ortolina
2025-04-09 18:41:18 +01:00
parent 04f2bd8183
commit 2ae6adf72f
@@ -28,73 +28,79 @@ defmodule MusicLibraryWeb.ChartComponents do
assigns assigns
|> assign(:padding, 40) |> assign(:padding, 40)
|> assign(:max_value, max_value(assigns.data, assigns.value_fn)) |> assign(:max_value, max_value(assigns.data, assigns.value_fn))
# Account for labels # Account for labels and padding
|> assign(:chart_width, assigns.width - 150) |> assign(:chart_width, assigns.width - 150 - 40)
# Account for bottom padding # Account for bottom padding
|> assign(:chart_height, assigns.height - 40) |> assign(:chart_height, assigns.height - 40)
|> assign(:bar_height, calculate_bar_height(assigns.data, assigns.height - 40)) |> assign(:bar_height, calculate_bar_height(assigns.data, assigns.height - 40))
~H""" ~H"""
<svg class={@class} width={@width} height={@height}> <div class={["w-full", @class]}>
<%!-- X-axis labels and lines --%> <svg
<%= for {value, x} <- x_axis_values(@max_value, @chart_width) do %> viewBox={"0 0 #{@width} #{@height}"}
<text preserveAspectRatio="xMidYMid meet"
x={x + 150} class="w-full h-full"
y={@height - 10} >
text-anchor="middle" <%!-- X-axis labels and lines --%>
class="text-xs fill-zinc-500 dark:fill-zinc-400" <%= for {value, x} <- x_axis_values(@max_value, @chart_width) do %>
> <text
{value} x={x + 150}
</text> y={@height - 10}
<line text-anchor="middle"
x1={x + 150} class="text-xs fill-zinc-500 dark:fill-zinc-400"
y1={@padding / 2} >
x2={x + 150} {value}
y2={@height - @padding / 2} </text>
stroke="rgb(228, 228, 231)" <line
stroke-width="1" x1={x + 150}
stroke-dasharray="4,4" y1={@padding / 2}
/> x2={x + 150}
<% end %> y2={@height - @padding / 2}
stroke="rgb(228, 228, 231)"
stroke-width="1"
stroke-dasharray="4,4"
/>
<% end %>
<%!-- Bars and labels --%> <%!-- Bars and labels --%>
<%= for {datum, index} <- Enum.with_index(@data) do %> <%= for {datum, index} <- Enum.with_index(@data) do %>
<% bar_width = @chart_width * @value_fn.(datum) / @max_value %> <% bar_width = @chart_width * @value_fn.(datum) / @max_value %>
<% y = @padding / 2 + index * (@bar_height + 4) %> <% y = @padding / 2 + index * (@bar_height + 4) %>
<%!-- Label --%> <%!-- Label --%>
<text <text
x="140" x="140"
y={y + @bar_height / 2 + 4} y={y + @bar_height / 2 + 4}
text-anchor="end" text-anchor="end"
class={["text-xs fill-zinc-500 dark:fill-zinc-400", @label_click && "cursor-pointer"]} class={["text-xs fill-zinc-500 dark:fill-zinc-400", @label_click && "cursor-pointer"]}
phx-click={@label_click && @label_click.(datum)} phx-click={@label_click && @label_click.(datum)}
> >
{truncate_label(@label_fn.(datum), 20)} {truncate_label(@label_fn.(datum), 20)}
</text> </text>
<%!-- Bar --%> <%!-- Bar --%>
<rect <rect
x="150" x="150"
y={y} y={y}
width={bar_width} width={bar_width}
height={@bar_height} height={@bar_height}
fill={@bar_color} fill={@bar_color}
class="opacity-80 hover:opacity-100 transition-opacity" class="opacity-80 hover:opacity-100 transition-opacity"
> >
<title>{@label_fn.(datum)}: {@value_fn.(datum)}</title> <title>{@label_fn.(datum)}: {@value_fn.(datum)}</title>
</rect> </rect>
<%!-- Value label --%> <%!-- Value label --%>
<text <text
x={150 + bar_width + 5} x={150 + bar_width + 5}
y={y + @bar_height / 2 + 4} y={y + @bar_height / 2 + 4}
class="text-xs fill-zinc-500 dark:fill-zinc-400" class="text-xs fill-zinc-500 dark:fill-zinc-400"
> >
{@value_fn.(datum)} {@value_fn.(datum)}
</text> </text>
<% end %> <% end %>
</svg> </svg>
</div>
""" """
end end