defmodule PlausibleWeb.Live.Components.Visitors do @moduledoc """ Component rendering mini-graph of site's visitors over the last 24 hours. The `gradient_defs` component should be rendered once before using `chart` one or more times. Accepts input generated via `Plausible.Stats.Clickhouse.last_24h_visitors_hourly_intervals/2`. """ use Phoenix.Component attr :intervals, :list, required: true attr :height, :integer, default: 50 attr :tick, :integer, default: 20 def chart(assigns) do points = assigns.intervals |> scale(assigns.height) |> Enum.with_index(fn scaled_value, index -> "#{index * assigns.tick},#{scaled_value}" end) clip_points = List.flatten([ "0,#{assigns.height + 1}", points, "#{(length(points) - 1) * assigns.tick},#{assigns.height + 1}", "0,#{assigns.height + 1}" ]) assigns = assigns |> assign(:points_len, length(points)) |> assign(:points, Enum.join(points, " ")) |> assign(:clip_points, Enum.join(clip_points, " ")) |> assign(:id, Ecto.UUID.generate()) ~H""" """ end def gradient_defs(assigns) do ~H""" """ end defp scale(data, target_range) do max_value = Enum.max_by(data, fn %{visitors: visitors} -> visitors end) scaling_factor = if max_value.visitors > 0, do: target_range / max_value.visitors, else: 0 Enum.map(data, fn %{visitors: visitors} -> round(target_range - visitors * scaling_factor) end) end end