Skip to content

Instantly share code, notes, and snippets.

@sb8244
Created May 16, 2021
Embed
What would you like to do?
This allows chartkick to be embedded in LiveViews
defmodule Chartkick do
@moduledoc """
Adapted from https://github.com/buren/chartkick-ex/blob/master/lib/chartkick.ex to work with LiveView.
Works in conjunction with Phoenix LiveView hooks to render charts using Chartkick.js library.
"""
require EEx
gen_chart_fn = fn chart_type ->
def unquote(
chart_type
|> Macro.underscore()
|> String.to_atom()
)(
data_source,
options \\ []
) do
chartkick_chart(unquote(chart_type), data_source, options)
end
end
Enum.map(
~w(LineChart PieChart BarChart AreaChart ColumnChart ComboChart GeoChart ScatterChart Timeline),
gen_chart_fn
)
def chartkick_chart(klass, data_source, options \\ []) do
id = Keyword.get_lazy(options, :id, &Ecto.UUID.generate/0)
height = Keyword.get(options, :height, "300px")
width = Keyword.get(options, :width, "100%")
only = Keyword.get(options, :only)
case only do
:html ->
chartkick_tag(id, height, width)
:script ->
chartkick_script(klass, id, data_source, options)
_ ->
"""
#{chartkick_tag(id, height, width)}
#{chartkick_script(klass, id, data_source, options)}
"""
end
end
EEx.function_from_string(
:def,
:chartkick_script,
~s[<div id="<%= id %>-loader"
data-klass="<%= klass %>"
data-id="<%= id %>"
data-source="<%= data_json(data_source) %>"
data-options="<%= options_json(options) %>"
phx-hook="Chartkick"
></div>],
~w(klass id data_source options)a
)
EEx.function_from_string(
:def,
:chartkick_tag,
~s[<div id="<%= id %>" style="width: <%= width %>; height: <%= height %>; text-align: center; color: #999; line-height: <%= height %>; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif;">Loading...</div>],
~w(id height width)a
)
defp options_json(opts) when is_list(opts) do
opts
|> Keyword.get(:chart_opts, [])
|> Enum.into(%{})
|> json_serializer().encode!()
|> Plug.HTML.html_escape()
end
defp options_json(opts) when is_bitstring(opts) do
opts
end
defp data_json(data) do
data
|> json_serializer().encode!()
|> Plug.HTML.html_escape()
end
defp json_serializer do
Application.get_env(:chartkick, :json_serializer, Jason)
end
end
import Chartkick from 'chartkick'
import 'chartkick/chart.js'
const ChartkickHook = {
mounted() {
const chartId = this.el.dataset.id
const dataSource = JSON.parse(this.el.dataset.source)
const options = JSON.parse(this.el.dataset.options)
const klass = this.el.dataset.klass
this.chart = new Chartkick[klass](chartId, dataSource, options)
},
destroyed() {
if (this.chart) {
this.chart.destroy()
}
}
}
export const hooks = {
Chartkick: ChartkickHook
}
# File excluded for brevity, just the template aspect
~L"""
<%= raw Chartkick.line_chart(@chart_data, chart_opts: [dataset: %{tension: 0.1}]) %>
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment