Skip to content

Stax3/live_charts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LiveCharts

LiveCharts allows you to render static and dynamic charts in Phoenix LiveView applications.

LiveCharts currently comes with support for ApexCharts out of the box, but it can work with any JS charting library that has a LiveCharts.Adapter defined.

To see live demos, visit: livecharts.stax3.com.

Installation

Add :live_charts to your mix.exs dependencies:

defp deps do
  [
    {:live_charts, "~> 0.3.0"},
  ]
end

Then include the LiveCharts hooks in your app.js:

// Import the JS file
import LiveCharts from "live_charts"

// Include the hooks
let liveSocket = new LiveSocket("/live", Socket, {
  params: {_csrf_token: csrfToken},
  hooks: {
    // your other hooks...
    // e.g. SomeCustomHook,

    // Expand LiveCharts hooks at the end
    ...LiveCharts.Hooks,
  },
});

Configuration

LiveCharts may optionally be configured to set the default adapter or JSON encoding library. It currently defaults to the following:

# config/config.exs

config :live_charts,
  adapter: LiveCharts.Adapter.ApexCharts,
  json_library: Jason

Usage

Chart data

LiveCharts tracks a chart's data and configuration in a %Chart{} struct. Before it can be rendered, you need to build this struct.

my_chart =
  LiveCharts.build(%{
    # (Optional) a unique string id to differentiate the chart from other
    # charts on the same page. If not set, a random id will be assigned
    # to the chart.
    id: "my-custom-chart-id",

    # Set the chart type. Supports `:line`, `:bar`, `:pie`, `:donut`,
    # `:area`, and many more. For a full list of supported types, see the
    # adapter or JS library documentation.
    type: :bar,

    # A list of series data with all the datapoints to chart. Format of
    # this data is determined by the adapter/JS library. This may also
    # be empty, if you plan to push dynamic updates to the chart over
    # the socket later.
    series: [
      %{name: "Sales", data: [10, 20, 30, 40, 50]},
    ],

    # (Optional) Other library and adapter-specific options.
    options: %{
      xaxis: %{
        categories: [2021, 2022, 2023, 2024, 2025]
      },
    },

    # (Optional) set the adapter to use for the chart. If not set, uses
    # the global adapter configured in `config.exs` (defaults to
    # `LiveCharts.Adapter.ApexCharts`).
    adapter: LiveCharts.Adapter.ApexCharts,
  })

For a full list of options, see the official ApexCharts docs and the LiveCharts.Adapter.ApexCharts adapter information on HexDocs. You can also view live demos here.

Render Static Charts

With a LiveCharts.Chart struct defined, you can now assign it in your liveview:

def mount(_params, _session, socket) do
  socket =
    socket
    |> assign(:page_title, "Page with charts!")
    |> assign(:my_chart, my_chart)

  {:ok, socket}
end

To then render the chart in a heex template, use LiveCharts.chart/1 component:

<LiveCharts.chart chart={@my_chart} />

This will re-render the chart on the page any time the chart assign is changed or updated.

Push Realtime/Dynamic updates to the Chart

If the chart needs to be updated often, a better strategy is to only push the new data instead of rebuilding the entire chart and re-rendering it. You can do so by calling:

LiveCharts.push_update(socket, chart.id, updated_series)

Example

Let's say we want to render a line chart that starts out empty, but as we get datapoints from an external source, we want to push them to the users' browsers.

We'll start by assigning a line chart to the LiveView:

@impl true
def mount(_params, _session, socket) do
  # Build an empty chart with custom settings
  chart = LiveCharts.build(%{
    type: :line,
    series: [],
    options: %{
      xaxis: %{type: "datetime"},
      yaxis: %{min: 0, max: 100},
      chart: %{
        animations: %{enabled: true, easing: "linear"},
        zoom: %{enabled: false}
      }
    }
  })

  socket =
    socket
    |> assign(:chart, chart)
    |> assign(:chart_data, [])

  {:ok, socket}
end

Then, render the empty chart in your heex template:

<LiveCharts.chart chart={@chart} />

Assuming you already have a mechanism in place to receive new data points in the liveview, you can then update the chart data and push it over the socket:

@impl true
def handle_info({:chart_datapoint, {x, y}}, socket) do
  %{chart: chart, chart_data: data} = socket.assigns

  data = [%{x: x, y: y} | data]
  series = [%{data: Enum.reverse(data)}]

  socket =
    socket
    |> assign(:chart_data, data)
    |> LiveCharts.push_update(chart, series)

  {:noreply, socket}
end

We have used handle_info/2 here, but chart updates could just as easily be pushed from other liveview callbacks. E.g. from handle_event/3 when the user triggers an event or handle_async/3 when an async task is completed.

A live demo is also available on livecharts.stax3.com.

Looking for help with your Elixir project?

Stax3 helps startups craft expressive and engaging solutions for their software needs. If you're looking for expertise for your Elixir/Phoenix projects, we can help! Talk to us at [email protected].

License

LiveCharts is licensed under the MIT License.