# ChartJS
This plugin allows you to render Chart.js charts in Phoenix LiveView applications easily and reactively.
## Installation
### As a Published Package (Hex.pm)
Add `chart_js` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:chart_js, "~> 0.1.0"}
]
end
```
### Installing Chart.js Dependencies
After adding the dependency, install the required npm packages:
```bash
# Install Elixir dependencies
mix deps.get
# Install Chart.js npm dependencies
mix chart_js.install
```
### Setup for Development
To set up the Chart.js plugin project itself:
```bash
mix setup
```
## Quick Usage
1. **Add the component to your LiveView:**
```elixir
<.live_component
module={ChartJs.ChartComponent}
id="my_chart"
type="bar" # or "line", "pie", etc.
data={%{"labels" => ["A", "B"], "datasets" => [%{"label" => "Demo", "data" => [1,2]}]}}
options={%{}}
/>
```
2. **Include the JS hook in your app.js**
```javascript
import ChartJsHook from "../deps/chart_js/assets/chart_hook.js";
let Hooks = { ChartJs: ChartJsHook };
let liveSocket = new LiveSocket("/live", Socket, { hooks: Hooks });
```
3. **Done!**
Whenever the data or options change, the chart will automatically update.
---
## Real-time Chart Updates
You can update charts dynamically using `push_event` from your LiveView:
### Adding Data Points
```elixir
# Add a new data point to ALL charts (push_event/3)
push_event(socket, "add_chart_data", %{
"label" => "March", # new label (optional)
"datasets" => [
%{"data" => 25} # new data point for first dataset
]
})
# Add data to multiple datasets
push_event(socket, "add_chart_data", %{
"label" => "April",
"datasets" => [
%{"datasetIndex" => 0, "data" => 30}, # first dataset
%{"datasetIndex" => 1, "data" => 15} # second dataset
]
})
```
**Note:** With `push_event/3`, the event is sent to ALL chart components. If you need to target specific charts, you have two options:
### Option A: Include target in the event data and modify the hook
```elixir
# Send target in the event payload
push_event(socket, "add_chart_data", %{
"target" => "sales_chart", # chart component id
"label" => "Sales Data",
"datasets" => [%{"data" => 100}]
})
```
### Option B: Use separate event names for different charts
```elixir
# Different events for different charts
push_event(socket, "add_sales_chart_data", %{
"label" => "Q1", "datasets" => [%{"data" => 1500}]
})
push_event(socket, "add_users_chart_data", %{
"label" => "Q1", "datasets" => [%{"data" => 250}]
})
```
### Example LiveView Implementation
```elixir
defmodule MyAppWeb.ChartLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
if connected?(socket) do
:timer.send_interval(2000, self(), :update_chart)
end
socket = assign(socket, :chart_data, initial_chart_data())
{:ok, socket}
end
def handle_info(:update_chart, socket) do
new_value = :rand.uniform(100)
push_event(socket, "add_chart_data", %{
"label" => "Point #{System.system_time(:second)}",
"datasets" => [%{"data" => new_value}]
})
{:noreply, socket}
end
defp initial_chart_data do
%{
"labels" => ["Jan", "Feb"],
"datasets" => [
%{
"label" => "Sales",
"data" => [10, 20],
"backgroundColor" => "#3b82f6"
}
]
}
end
end
```
## Customization
You can pass any valid Chart.js configuration in `data` and `options`.
## Example data
```elixir
%{"labels" => ["Red", "Blue"],
"datasets" => [
%{"label" => "Votes", "data" => [12, 19], "backgroundColor" => ["#f00", "#00f"]}
]}
```
## Troubleshooting
### "Could not resolve 'chart.js/auto'" Error
If you see this error when using the plugin as a local dependency:
```
✘ [ERROR] Could not resolve "chart.js/auto"
```
**Solution:**
1. Make sure you've installed Chart.js dependencies:
```bash
mix chart_js.install
```
2. Or install manually:
```bash
cd assets
npm install chart.js
```
3. Verify the import path in your `app.js`:
```javascript
import ChartJsHook from "../deps/chart_js/assets/chart_hook.js";
```
### Multiple Charts Not Updating Correctly
Make sure each chart has a unique `id`:
```elixir
<.live_component module={ChartJs.ChartComponent} id="chart_1" ... />
<.live_component module={ChartJs.ChartComponent} id="chart_2" ... />
```
Use the `target` parameter for selective updates:
```elixir
push_event(socket, "add_chart_data", %{
"datasets" => [%{"data" => 42}]
}, target: "chart_1") # Only updates chart_1
```
## Notes
- The component renders a `<canvas>` and uses a hook to initialize Chart.js.
- The hook destroys the previous chart before creating a new one to avoid memory leaks.
- You can have multiple charts in the same view, just use different `id`s.
## Installation
The package can be installed by adding `chart_js` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:chart_js, "~> 0.1.0"}
]
end
```