diff --git a/lib/chart/sparkline.ex b/lib/chart/sparkline.ex
index efd547b..b8479a6 100644
--- a/lib/chart/sparkline.ex
+++ b/lib/chart/sparkline.ex
@@ -13,17 +13,49 @@ defmodule Contex.Sparkline do
Sparkline.new(data) |> Sparkline.draw() # Emits svg sparkline
```
- The colour defaults to a green line with a faded green fill, but can be overridden
- with `colours/3`. Unlike other colours in Contex, these colours are how you would
- specify them in CSS - e.g.
+ You can modify various rendering properties through `style/2`. These properties
+ map directly to the underlying elements (line & area), giving you great flexibility to
+ style them in various ways -e.g.
+
+ Use color values & dimensions:
+
```
Sparkline.new(data)
- |> Sparkline.colours("#fad48e", "#ff9838")
+ |> Sparkline.style(line_stroke: "#fad48e", area_fill: "#ff9838", height: 50, width: 300)
+ |> Sparkline.draw()
+ ```
+
+ Use classes:
+
+ ```
+ Sparkline.new(data)
+ |> Sparkline.style(
+ line_stroke: nil,
+ area_fill: nil,
+ line_class: "stroke-blue-500",
+ area_class: "fill-blue-50"
+ )
+ |> Sparkline.draw()
+ ```
+
+ Injecting extra_elements:
+
+ ```
+ extra_svg = \"""
+
+
+
+
+
+
+ \"""
+
+ Sparkline.new(data)
+ |> Sparkline.style(line_stroke: "url(#pretty-gradient)", extra_svg: extra_svg)
|> Sparkline.draw()
```
- The size defaults to 20 pixels high and 100 wide. You can override by updating
- `:height` and `:width` directly in the `Sparkline` struct before call `draw/1`.
+
"""
alias __MODULE__
alias Contex.{ContinuousLinearScale, Scale}
@@ -32,25 +64,45 @@ defmodule Contex.Sparkline do
:data,
:extents,
:length,
- :spot_radius,
- :spot_colour,
- :line_width,
- :line_colour,
- :fill_colour,
:y_transform,
:height,
- :width
+ :width,
+ :extra_svg,
+ :line_stroke,
+ :line_class,
+ :line_stroke_width,
+ :line_stroke_linecap,
+ :line_stroke_linejoin,
+ :line_fill,
+ :area_stroke,
+ :area_fill,
+ :area_class
]
@type t() :: %__MODULE__{}
+ @default_style [
+ height: 20,
+ width: 100,
+ extra_svg: nil,
+ line_stroke: "rgba(0, 200, 50, 0.7)",
+ line_class: nil,
+ line_stroke_width: 1,
+ line_stroke_linecap: "round",
+ line_stroke_linejoin: "round",
+ line_fill: "none",
+ area_stroke: "none",
+ area_fill: "rgba(0, 200, 50, 0.2)",
+ area_class: nil
+ ]
+
@doc """
Create a new sparkline struct from some data.
"""
@spec new([number()]) :: Contex.Sparkline.t()
def new(data) when is_list(data) do
%Sparkline{data: data, extents: ContinuousLinearScale.extents(data), length: length(data)}
- |> set_default_style
+ |> style()
end
@doc """
@@ -65,77 +117,161 @@ defmodule Contex.Sparkline do
|> Sparkline.draw()
```
"""
+ @deprecated "Use style/2 instead"
+ @since "0.5.0"
@spec colours(Contex.Sparkline.t(), String.t(), String.t()) :: Contex.Sparkline.t()
- def colours(%Sparkline{} = sparkline, fill, line) do
+ def colours(%Sparkline{} = sparkline, area_fill, line_stroke) do
# TODO: Really need some validation...
- %{sparkline | fill_colour: fill, line_colour: line}
+ style(sparkline, area_fill: area_fill, line_stroke: line_stroke)
end
- defp set_default_style(%Sparkline{} = sparkline) do
- %{
- sparkline
- | spot_radius: 2,
- spot_colour: "red",
- line_width: 1,
- line_colour: "rgba(0, 200, 50, 0.7)",
- fill_colour: "rgba(0, 200, 50, 0.2)",
- height: 20,
- width: 100
- }
+ @doc """
+ Override any of the style settings for the sparkline.
+
+ There are 3 elements in a sparkline, wrapping svg, a line and an area.
+ To control how they are rendered, you can pass ony of the following
+ parameters:
+
+ * height: 20
+ * width: 100
+ * extra_svg: nil
+ * line_stroke: "rgba(0, 200, 50, 0.7)"
+ * line_class: nil
+ * line_stroke_width: 1
+ * line_stroke_linecap: "round"
+ * line_stroke_linejoin: "round"
+ * line_fill: "none"
+ * area_stroke: "none"
+ * area_fill: "rgba(0, 200, 50, 0.2)"
+ * area_class: nil
+
+ Example 1: Set color values & dimensions:
+
+ ```
+ Sparkline.new(data)
+ |> Sparkline.style(line_stroke: "#fad48e", area_fill: "#ff9838", height: 50, width: 300)
+ |> Sparkline.draw()
+ ```
+
+ Example 2: Set classes
+
+ ```
+ Sparkline.new(data)
+ |> Sparkline.style(
+ line_stroke: nil,
+ area_fill: nil,
+ line_class: "stroke-blue-500",
+ area_class: "fill-blue-50"
+ )
+ |> Sparkline.draw()
+ ```
+
+ Example 3: Add a gradient
+
+ ```
+ extra_svg = \"""
+
+
+
+
+
+
+ \"""
+
+ Sparkline.new(data)
+ |> Sparkline.style(line_stroke: "url(#pretty-gradient)", extra_svg: extra_svg)
+ |> Sparkline.draw()
+ ```
+ """
+ @spec style(Contex.Sparkline.t(),
+ height: :integer,
+ width: :integer,
+ extra_svg: String.t() | nil,
+ line_stroke: :integer,
+ line_class: String.t() | nil,
+ line_stroke_width: :integer,
+ line_stroke_linecap: String.t() | nil,
+ line_stroke_linejoin: String.t() | nil,
+ line_fill: String.t() | nil,
+ area_stroke: String.t() | nil,
+ area_fill: String.t() | nil,
+ area_class: String.t() | nil
+ ) :: Contex.Sparkline.t()
+ def style(%Sparkline{} = sparkline, options \\ []) do
+ props =
+ @default_style
+ |> Keyword.merge(options)
+ |> Enum.into(%{})
+
+ Map.merge(sparkline, props)
end
@doc """
Renders the sparkline to svg, including the svg wrapper, as a string or improper string list that
is marked safe.
"""
- def draw(%Sparkline{height: height, width: width, line_width: line_width} = sparkline) do
- vb_width = sparkline.length + 1
- vb_height = height - 2 * line_width
+ def draw(%Sparkline{} = chart) do
+ vb_width = chart.length - 1
+ vb_height = chart.height - 2 * chart.line_stroke_width
scale =
ContinuousLinearScale.new()
- |> ContinuousLinearScale.domain(sparkline.data)
- |> Scale.set_range(vb_height, 0)
+ |> ContinuousLinearScale.domain(chart.data)
+ |> Scale.set_range(chart.line_stroke_width / 2, vb_height)
- sparkline = %{sparkline | y_transform: Scale.domain_to_range_fn(scale)}
+ chart = %{chart | y_transform: Scale.domain_to_range_fn(scale)}
output = ~s"""
-