trackplot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/app/assets/javascripts/trackplot/index.js +1541 -0
- data/app/helpers/trackplot/chart_helper.rb +9 -0
- data/config/importmap.rb +2 -0
- data/lib/generators/trackplot/install_generator.rb +23 -0
- data/lib/trackplot/chart_builder.rb +119 -0
- data/lib/trackplot/components/area.rb +24 -0
- data/lib/trackplot/components/axis.rb +40 -0
- data/lib/trackplot/components/bar.rb +23 -0
- data/lib/trackplot/components/base.rb +19 -0
- data/lib/trackplot/components/candlestick.rb +17 -0
- data/lib/trackplot/components/funnel.rb +20 -0
- data/lib/trackplot/components/grid.rb +13 -0
- data/lib/trackplot/components/horizontal_bar.rb +22 -0
- data/lib/trackplot/components/legend.rb +13 -0
- data/lib/trackplot/components/line.rb +25 -0
- data/lib/trackplot/components/pie.rb +23 -0
- data/lib/trackplot/components/radar.rb +24 -0
- data/lib/trackplot/components/reference_line.rb +24 -0
- data/lib/trackplot/components/scatter.rb +24 -0
- data/lib/trackplot/components/tooltip.rb +29 -0
- data/lib/trackplot/data_adapter.rb +33 -0
- data/lib/trackplot/engine.rb +22 -0
- data/lib/trackplot/theme.rb +59 -0
- data/lib/trackplot/version.rb +3 -0
- data/lib/trackplot.rb +26 -0
- metadata +97 -0
data/config/importmap.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
desc "Install Trackplot into your Rails application"
|
|
5
|
+
|
|
6
|
+
def add_import
|
|
7
|
+
js_file = Rails.root.join("app/javascript/application.js")
|
|
8
|
+
|
|
9
|
+
if File.exist?(js_file)
|
|
10
|
+
content = File.read(js_file)
|
|
11
|
+
if content.include?('import "trackplot"')
|
|
12
|
+
say "trackplot import already present in application.js", :yellow
|
|
13
|
+
else
|
|
14
|
+
append_to_file js_file, "\nimport \"trackplot\"\n"
|
|
15
|
+
say "Added trackplot import to application.js", :green
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
say "Could not find app/javascript/application.js — please add `import \"trackplot\"` manually", :red
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require "securerandom"
|
|
2
|
+
require "json"
|
|
3
|
+
|
|
4
|
+
module Trackplot
|
|
5
|
+
class ChartBuilder
|
|
6
|
+
attr_reader :data, :options, :components
|
|
7
|
+
|
|
8
|
+
def initialize(data, **options)
|
|
9
|
+
@data = DataAdapter.normalize(data)
|
|
10
|
+
@options = options
|
|
11
|
+
@components = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def line(data_key, **opts)
|
|
15
|
+
@components << Components::Line.new(data_key, **opts)
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def bar(data_key, **opts)
|
|
20
|
+
@components << Components::Bar.new(data_key, **opts)
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def area(data_key, **opts)
|
|
25
|
+
@components << Components::Area.new(data_key, **opts)
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def pie(data_key, **opts)
|
|
30
|
+
@components << Components::Pie.new(data_key, **opts)
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def axis(direction, **opts)
|
|
35
|
+
@components << Components::Axis.new(direction, **opts)
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def tooltip(**opts)
|
|
40
|
+
@components << Components::Tooltip.new(**opts)
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def legend(**opts)
|
|
45
|
+
@components << Components::Legend.new(**opts)
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def grid(**opts)
|
|
50
|
+
@components << Components::Grid.new(**opts)
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def scatter(data_key, **opts)
|
|
55
|
+
@components << Components::Scatter.new(data_key, **opts)
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def radar(data_key, **opts)
|
|
60
|
+
@components << Components::Radar.new(data_key, **opts)
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def horizontal_bar(data_key, **opts)
|
|
65
|
+
@components << Components::HorizontalBar.new(data_key, **opts)
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def candlestick(**opts)
|
|
70
|
+
@components << Components::Candlestick.new(**opts)
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def funnel(data_key, **opts)
|
|
75
|
+
@components << Components::Funnel.new(data_key, **opts)
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def reference_line(**opts)
|
|
80
|
+
@components << Components::ReferenceLine.new(**opts)
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def render(view_context)
|
|
85
|
+
chart_id = options[:id] || "trackplot-#{SecureRandom.hex(8)}"
|
|
86
|
+
config = build_config
|
|
87
|
+
|
|
88
|
+
view_context.content_tag(
|
|
89
|
+
"trackplot-chart",
|
|
90
|
+
nil,
|
|
91
|
+
id: chart_id,
|
|
92
|
+
config: config.to_json,
|
|
93
|
+
style: chart_style,
|
|
94
|
+
class: css_classes
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def build_config
|
|
101
|
+
{
|
|
102
|
+
data: data,
|
|
103
|
+
components: components.map(&:to_config),
|
|
104
|
+
animate: options.fetch(:animate, true),
|
|
105
|
+
theme: Theme.resolve(options[:theme])
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def chart_style
|
|
110
|
+
width = options[:width] || "100%"
|
|
111
|
+
height = options[:height] || "400px"
|
|
112
|
+
"display:block;width:#{width};height:#{height};"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def css_classes
|
|
116
|
+
["trackplot-chart", options[:class]].compact.join(" ")
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Area < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "area",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
color: options[:color],
|
|
16
|
+
curve: options.fetch(:curve, false),
|
|
17
|
+
opacity: options[:opacity] || 0.3,
|
|
18
|
+
stroke_width: options[:stroke_width] || 2,
|
|
19
|
+
stack: options[:stack]
|
|
20
|
+
}.compact
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Axis < Base
|
|
4
|
+
FORMAT_SYMBOLS = {
|
|
5
|
+
currency: "currency",
|
|
6
|
+
percent: "percent",
|
|
7
|
+
compact: "compact",
|
|
8
|
+
decimal: "decimal",
|
|
9
|
+
integer: "integer"
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
attr_reader :direction
|
|
13
|
+
|
|
14
|
+
def initialize(direction, **options)
|
|
15
|
+
@direction = direction.to_s
|
|
16
|
+
super(**options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_config
|
|
20
|
+
{
|
|
21
|
+
type: "axis",
|
|
22
|
+
direction: direction,
|
|
23
|
+
data_key: options[:data_key],
|
|
24
|
+
label: options[:label],
|
|
25
|
+
format: resolve_format(options[:format]),
|
|
26
|
+
tick_count: options[:tick_count],
|
|
27
|
+
tick_rotation: options[:tick_rotation]
|
|
28
|
+
}.compact
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def resolve_format(fmt)
|
|
34
|
+
return nil if fmt.nil?
|
|
35
|
+
|
|
36
|
+
FORMAT_SYMBOLS.fetch(fmt, fmt).to_s
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Bar < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "bar",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
color: options[:color],
|
|
16
|
+
opacity: options[:opacity],
|
|
17
|
+
radius: options[:radius] || 4,
|
|
18
|
+
stack: options[:stack]
|
|
19
|
+
}.compact
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Base
|
|
4
|
+
attr_reader :options
|
|
5
|
+
|
|
6
|
+
def initialize(**options)
|
|
7
|
+
@options = options
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def type
|
|
11
|
+
self.class.name.demodulize.underscore
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_config
|
|
15
|
+
{type: type}.merge(options).compact
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Candlestick < Base
|
|
4
|
+
def to_config
|
|
5
|
+
{
|
|
6
|
+
type: "candlestick",
|
|
7
|
+
open: options[:open],
|
|
8
|
+
high: options[:high],
|
|
9
|
+
low: options[:low],
|
|
10
|
+
close: options[:close],
|
|
11
|
+
up_color: options[:up_color] || "#10b981",
|
|
12
|
+
down_color: options[:down_color] || "#ef4444"
|
|
13
|
+
}.compact
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Funnel < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "funnel",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
label_key: options[:label_key]
|
|
16
|
+
}.compact
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class HorizontalBar < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "horizontal_bar",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
color: options[:color],
|
|
16
|
+
opacity: options[:opacity],
|
|
17
|
+
radius: options[:radius] || 4
|
|
18
|
+
}.compact
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Line < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "line",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
color: options[:color],
|
|
16
|
+
curve: options.fetch(:curve, false),
|
|
17
|
+
dashed: options.fetch(:dashed, false),
|
|
18
|
+
stroke_width: options[:stroke_width] || 2,
|
|
19
|
+
dot: options.fetch(:dot, true),
|
|
20
|
+
dot_size: options[:dot_size] || 4
|
|
21
|
+
}.compact
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Pie < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "pie",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
label_key: options[:label_key],
|
|
16
|
+
donut: options.fetch(:donut, false),
|
|
17
|
+
inner_radius: options[:inner_radius],
|
|
18
|
+
pad_angle: options[:pad_angle] || 0.02
|
|
19
|
+
}.compact
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Radar < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "radar",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
color: options[:color],
|
|
16
|
+
opacity: options[:opacity] || 0.15,
|
|
17
|
+
stroke_width: options[:stroke_width] || 2,
|
|
18
|
+
dot: options.fetch(:dot, true),
|
|
19
|
+
dot_size: options[:dot_size] || 4
|
|
20
|
+
}.compact
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class ReferenceLine < Base
|
|
4
|
+
def initialize(**options)
|
|
5
|
+
super
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def to_config
|
|
9
|
+
direction = options[:y] ? "y" : "x"
|
|
10
|
+
value = options[:y] || options[:x]
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
type: "reference_line",
|
|
14
|
+
direction: direction,
|
|
15
|
+
value: value,
|
|
16
|
+
label: options[:label],
|
|
17
|
+
color: options[:color] || "#ef4444",
|
|
18
|
+
dashed: options.fetch(:dashed, true),
|
|
19
|
+
stroke_width: options[:stroke_width] || 1.5
|
|
20
|
+
}.compact
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Scatter < Base
|
|
4
|
+
attr_reader :data_key
|
|
5
|
+
|
|
6
|
+
def initialize(data_key, **options)
|
|
7
|
+
@data_key = data_key
|
|
8
|
+
super(**options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_config
|
|
12
|
+
{
|
|
13
|
+
type: "scatter",
|
|
14
|
+
data_key: data_key,
|
|
15
|
+
x_key: options[:x_key],
|
|
16
|
+
color: options[:color],
|
|
17
|
+
dot_size: options[:dot_size] || 5,
|
|
18
|
+
opacity: options[:opacity] || 0.7,
|
|
19
|
+
shape: options[:shape] || "circle"
|
|
20
|
+
}.compact
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
module Components
|
|
3
|
+
class Tooltip < Base
|
|
4
|
+
FORMAT_SYMBOLS = {
|
|
5
|
+
currency: "currency",
|
|
6
|
+
percent: "percent",
|
|
7
|
+
compact: "compact",
|
|
8
|
+
decimal: "decimal",
|
|
9
|
+
integer: "integer"
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
def to_config
|
|
13
|
+
{
|
|
14
|
+
type: "tooltip",
|
|
15
|
+
format: resolve_format(options[:format]),
|
|
16
|
+
label_format: options[:label_format]
|
|
17
|
+
}.compact
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def resolve_format(fmt)
|
|
23
|
+
return nil if fmt.nil?
|
|
24
|
+
|
|
25
|
+
FORMAT_SYMBOLS.fetch(fmt, fmt).to_s
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
class DataAdapter
|
|
3
|
+
def self.normalize(data)
|
|
4
|
+
records = case data
|
|
5
|
+
when ->(d) { defined?(ActiveRecord::Relation) && d.is_a?(ActiveRecord::Relation) }
|
|
6
|
+
data.map { |record| to_string_hash(record.attributes) }
|
|
7
|
+
when Array
|
|
8
|
+
data.map { |item| coerce_record(item) }
|
|
9
|
+
when Hash
|
|
10
|
+
[data.transform_keys(&:to_s)]
|
|
11
|
+
else
|
|
12
|
+
Array(data).map { |item| coerce_record(item) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
records.map { |r| r.transform_keys(&:to_s) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.coerce_record(item)
|
|
19
|
+
case item
|
|
20
|
+
when Hash
|
|
21
|
+
item
|
|
22
|
+
when ->(i) { i.respond_to?(:attributes) }
|
|
23
|
+
item.attributes
|
|
24
|
+
when ->(i) { i.respond_to?(:to_h) }
|
|
25
|
+
item.to_h
|
|
26
|
+
else
|
|
27
|
+
raise ArgumentError, "Trackplot: cannot convert #{item.class} to chart data. Expected Hash, ActiveRecord, or an object responding to #to_h."
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private_class_method :coerce_record
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
|
+
isolate_namespace Trackplot
|
|
4
|
+
|
|
5
|
+
initializer "trackplot.helpers" do
|
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
|
7
|
+
include Trackplot::ChartHelper
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
initializer "trackplot.assets" do |app|
|
|
12
|
+
app.config.assets.paths << root.join("app/assets/javascripts") if app.config.respond_to?(:assets)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
initializer "trackplot.importmap", before: "importmap" do |app|
|
|
16
|
+
if app.config.respond_to?(:importmap)
|
|
17
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
|
18
|
+
app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Trackplot
|
|
2
|
+
class Theme
|
|
3
|
+
PRESETS = {
|
|
4
|
+
default: {
|
|
5
|
+
colors: ["#6366f1", "#06b6d4", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899", "#14b8a6"],
|
|
6
|
+
background: "transparent",
|
|
7
|
+
text_color: "#374151",
|
|
8
|
+
axis_color: "#d1d5db",
|
|
9
|
+
grid_color: "#e5e7eb",
|
|
10
|
+
tooltip_bg: "rgba(255, 255, 255, 0.96)",
|
|
11
|
+
tooltip_text: "#111827",
|
|
12
|
+
tooltip_border: "#e5e7eb",
|
|
13
|
+
font: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
14
|
+
},
|
|
15
|
+
dark: {
|
|
16
|
+
colors: ["#818cf8", "#22d3ee", "#34d399", "#fbbf24", "#f87171", "#a78bfa", "#f472b6", "#2dd4bf"],
|
|
17
|
+
background: "#1e1e2e",
|
|
18
|
+
text_color: "#e2e8f0",
|
|
19
|
+
axis_color: "#4a5568",
|
|
20
|
+
grid_color: "#2d3748",
|
|
21
|
+
tooltip_bg: "rgba(30, 30, 46, 0.96)",
|
|
22
|
+
tooltip_text: "#f1f5f9",
|
|
23
|
+
tooltip_border: "#4a5568",
|
|
24
|
+
font: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
25
|
+
},
|
|
26
|
+
vibrant: {
|
|
27
|
+
colors: ["#ff6b6b", "#ffd93d", "#6bcb77", "#4d96ff", "#ff922b", "#cc5de8", "#20c997", "#f06595"],
|
|
28
|
+
background: "transparent",
|
|
29
|
+
text_color: "#2d3436",
|
|
30
|
+
axis_color: "#b2bec3",
|
|
31
|
+
grid_color: "#dfe6e9",
|
|
32
|
+
tooltip_bg: "rgba(255, 255, 255, 0.96)",
|
|
33
|
+
tooltip_text: "#2d3436",
|
|
34
|
+
tooltip_border: "#dfe6e9",
|
|
35
|
+
font: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
36
|
+
},
|
|
37
|
+
minimal: {
|
|
38
|
+
colors: ["#475569", "#94a3b8", "#334155", "#64748b", "#1e293b", "#78716c", "#57534e", "#a8a29e"],
|
|
39
|
+
background: "transparent",
|
|
40
|
+
text_color: "#64748b",
|
|
41
|
+
axis_color: "#e2e8f0",
|
|
42
|
+
grid_color: "#f1f5f9",
|
|
43
|
+
tooltip_bg: "rgba(255, 255, 255, 0.96)",
|
|
44
|
+
tooltip_text: "#334155",
|
|
45
|
+
tooltip_border: "#e2e8f0",
|
|
46
|
+
font: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
47
|
+
}
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
def self.resolve(option)
|
|
51
|
+
case option
|
|
52
|
+
when nil then PRESETS[:default]
|
|
53
|
+
when Symbol then PRESETS.fetch(option) { raise ArgumentError, "Unknown theme: #{option}. Available: #{PRESETS.keys.join(", ")}" }
|
|
54
|
+
when Hash then PRESETS[:default].merge(option.transform_keys(&:to_sym))
|
|
55
|
+
else raise ArgumentError, "Theme must be a Symbol, Hash, or nil"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/trackplot.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative "trackplot/version"
|
|
2
|
+
require_relative "trackplot/engine" if defined?(Rails::Engine)
|
|
3
|
+
|
|
4
|
+
module Trackplot
|
|
5
|
+
autoload :ChartBuilder, "trackplot/chart_builder"
|
|
6
|
+
autoload :DataAdapter, "trackplot/data_adapter"
|
|
7
|
+
autoload :Theme, "trackplot/theme"
|
|
8
|
+
|
|
9
|
+
module Components
|
|
10
|
+
autoload :Base, "trackplot/components/base"
|
|
11
|
+
autoload :Line, "trackplot/components/line"
|
|
12
|
+
autoload :Bar, "trackplot/components/bar"
|
|
13
|
+
autoload :Area, "trackplot/components/area"
|
|
14
|
+
autoload :Pie, "trackplot/components/pie"
|
|
15
|
+
autoload :Axis, "trackplot/components/axis"
|
|
16
|
+
autoload :Tooltip, "trackplot/components/tooltip"
|
|
17
|
+
autoload :Legend, "trackplot/components/legend"
|
|
18
|
+
autoload :Grid, "trackplot/components/grid"
|
|
19
|
+
autoload :Scatter, "trackplot/components/scatter"
|
|
20
|
+
autoload :Radar, "trackplot/components/radar"
|
|
21
|
+
autoload :HorizontalBar, "trackplot/components/horizontal_bar"
|
|
22
|
+
autoload :Candlestick, "trackplot/components/candlestick"
|
|
23
|
+
autoload :Funnel, "trackplot/components/funnel"
|
|
24
|
+
autoload :ReferenceLine, "trackplot/components/reference_line"
|
|
25
|
+
end
|
|
26
|
+
end
|