A chart as plain data, to save and load back.
spec = Fude.Spec.dump(chart)
#=> %{"fude" => 1, "kind" => "bar", "x" => "region", "y" => %{"field" => "revenue", "aggregate" => "sum"}}
{:ok, chart} = Fude.Spec.load(spec)A spec is a map with string keys and JSON values, so it goes into a
:map column, a JSON file or a message as it is, and
load(dump(chart)) is the chart again. It carries its version
("fude" => 1): load/1 takes the specs of every earlier version and
gives today's chart.
A spec does not hold the chart's data: it names it ("data" => "sales"), and the chart gets it when it draws. dump(chart, data: true) puts the data in ("datasets"), for a file that stands alone.
The shape
A chart of one layer has its kind, channels and options at the top:
%{
"fude" => 1,
"kind" => "line",
"title" => "Visits",
"x" => %{"field" => "day", "time" => "week"},
"y" => "count",
"color" => "source",
"curve" => "monotone"
}A chart of several layers has them in "layers", each with its kind,
channels and options:
%{"fude" => 1, "layers" => [%{"kind" => "area", ...}, %{"kind" => "rule", "y" => 1000}]}A layer, and an annotation, may have an "id", text that names it
among the others: a chart shared with Fude.Issho gives each one, so
that two people who change two layers at once both have their change.
A channel is a field's name, or a map of the keys of Fude.Channel
("format" => "currency:EUR" for {:currency, "EUR"}); a constant is
%{"value" => 1000}.
Errors
load/1 checks the whole spec and gives every error, each with where it
is and what to do:
{:error, [%{path: ["y", "aggregate"], message: ~s|must be one of "count", "sum", ...; did you mean "sum"?|}]}
Summary
Types
An error of a spec: where (a path of keys and indexes), and what is wrong.
A spec: a map with string keys and JSON values.
Functions
The chart as a spec. With data: true, the spec holds the chart's data
too, under "datasets", as Fude.Data normalizes it. With layers: true, a chart of one layer has it in "layers" too, as a chart of
several does.
The errors as lines of text, one for each: y.aggregate: must be ....
The chart of a spec, or every error of it. A spec of an earlier version is first migrated to this one.
The chart of a spec; raises an ArgumentError with every error.
Types
@type error() :: %{path: [String.t() | non_neg_integer()], message: String.t()}
An error of a spec: where (a path of keys and indexes), and what is wrong.
A spec: a map with string keys and JSON values.
Functions
@spec dump(Fude.Chart.t(), keyword()) :: t()
The chart as a spec. With data: true, the spec holds the chart's data
too, under "datasets", as Fude.Data normalizes it. With layers: true, a chart of one layer has it in "layers" too, as a chart of
several does.
The errors as lines of text, one for each: y.aggregate: must be ....
@spec load(t()) :: {:ok, Fude.Chart.t()} | {:error, [error()]}
The chart of a spec, or every error of it. A spec of an earlier version is first migrated to this one.
@spec load!(t()) :: Fude.Chart.t()
The chart of a spec; raises an ArgumentError with every error.
@spec version() :: pos_integer()
The version of the specs that dump/1 gives.