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.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Eagerworks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,363 @@
1
+ # Trackplot
2
+
3
+ **Drop-in D3.js charts for Rails.** Write Ruby, get beautiful interactive visualizations. No JavaScript required.
4
+
5
+ Trackplot gives you a Recharts-like DSL that feels right at home in your `.erb` templates. Under the hood it renders a `<trackplot-chart>` custom element powered by D3.js — with animations, tooltips, theming, and Turbo support out of the box.
6
+
7
+ ```erb
8
+ <%= trackplot_chart @monthly_sales do |c| %>
9
+ <% c.line :revenue, color: "#6366f1", curve: true %>
10
+ <% c.bar :orders, color: "#06b6d4", opacity: 0.6 %>
11
+ <% c.axis :x, data_key: :month %>
12
+ <% c.axis :y, format: :currency %>
13
+ <% c.tooltip format: :currency %>
14
+ <% c.reference_line y: 10_000, label: "Goal" %>
15
+ <% c.legend %>
16
+ <% c.grid %>
17
+ <% end %>
18
+ ```
19
+
20
+ That's it. No JavaScript files to write, no chart config objects to manage, no build step drama.
21
+
22
+ ---
23
+
24
+ ## 10 Chart Types
25
+
26
+ | Cartesian | Radial | Other |
27
+ |-----------|--------|-------|
28
+ | Line | Pie / Donut | Horizontal Bar |
29
+ | Bar | Radar | Funnel |
30
+ | Area (+ stacked) | | Candlestick (OHLC) |
31
+ | Scatter | | |
32
+
33
+ Mix and match freely — bars + lines on the same chart just work.
34
+
35
+ ## Installation
36
+
37
+ Add to your Gemfile:
38
+
39
+ ```ruby
40
+ gem "trackplot"
41
+ ```
42
+
43
+ ### With importmap (default Rails 7+)
44
+
45
+ You're done. The engine auto-registers D3 from CDN and pins the trackplot module.
46
+
47
+ ### With esbuild / jsbundling-rails
48
+
49
+ Install D3 and trackplot from npm:
50
+
51
+ ```bash
52
+ yarn add d3 trackplot
53
+ ```
54
+
55
+ Then import it in your `app/javascript/application.js`:
56
+
57
+ ```javascript
58
+ import "trackplot"
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ Pass any array of hashes (or ActiveRecord collection) and describe what you want:
64
+
65
+ ```erb
66
+ <%= trackplot_chart @data, height: "300px" do |c| %>
67
+ <% c.line :temperature, color: "#ef4444", curve: true %>
68
+ <% c.axis :x, data_key: :date %>
69
+ <% c.axis :y, label: "Temp (F)" %>
70
+ <% c.tooltip %>
71
+ <% c.grid %>
72
+ <% end %>
73
+ ```
74
+
75
+ Your data can use symbol or string keys — Trackplot normalizes both:
76
+
77
+ ```ruby
78
+ @data = [
79
+ { date: "Mon", temperature: 72 },
80
+ { date: "Tue", temperature: 68 },
81
+ { date: "Wed", temperature: 75 }
82
+ ]
83
+ ```
84
+
85
+ ## Chart Types
86
+
87
+ ### Line
88
+
89
+ ```erb
90
+ <% c.line :revenue, color: "#6366f1", curve: true, dashed: true %>
91
+ ```
92
+
93
+ Options: `color`, `curve` (smooth), `dashed`, `stroke_width`, `dot` (true/false), `dot_size`.
94
+
95
+ ### Bar
96
+
97
+ ```erb
98
+ <% c.bar :sales, color: "#06b6d4", opacity: 0.8, radius: 6 %>
99
+ ```
100
+
101
+ Multiple bar series render as grouped bars automatically. Options: `color`, `opacity`, `radius` (corner rounding), `stack` (group name for stacking).
102
+
103
+ ### Area
104
+
105
+ ```erb
106
+ <% c.area :revenue, color: "#8b5cf6", curve: true %>
107
+ ```
108
+
109
+ Renders a gradient fill with a stroke line. Stack multiple areas by giving them the same `stack` name:
110
+
111
+ ```erb
112
+ <% c.area :revenue, stack: "main", color: "#10b981", curve: true %>
113
+ <% c.area :costs, stack: "main", color: "#f59e0b", curve: true %>
114
+ ```
115
+
116
+ ### Scatter
117
+
118
+ ```erb
119
+ <% c.scatter :weight, color: "#ec4899", dot_size: 6 %>
120
+ ```
121
+
122
+ Options: `color`, `dot_size`, `opacity`, `x_key` (override x-axis key).
123
+
124
+ ### Pie / Donut
125
+
126
+ ```erb
127
+ <% c.pie :value, label_key: :segment %>
128
+ <% c.pie :value, label_key: :segment, donut: true %>
129
+ ```
130
+
131
+ Options: `label_key`, `donut`, `pad_angle`.
132
+
133
+ ### Radar
134
+
135
+ ```erb
136
+ <% c.radar :player_a, color: "#6366f1" %>
137
+ <% c.radar :player_b, color: "#ef4444" %>
138
+ ```
139
+
140
+ Options: `color`, `opacity`, `stroke_width`, `dot`, `dot_size`.
141
+
142
+ ### Horizontal Bar
143
+
144
+ ```erb
145
+ <% c.horizontal_bar :popularity, color: "#14b8a6" %>
146
+ ```
147
+
148
+ Same options as regular bar. The x-axis `data_key` becomes the category axis.
149
+
150
+ ### Candlestick
151
+
152
+ ```erb
153
+ <% c.candlestick open: :open, high: :high, low: :low, close: :close %>
154
+ ```
155
+
156
+ Options: `up_color`, `down_color`.
157
+
158
+ ### Funnel
159
+
160
+ ```erb
161
+ <% c.funnel :count, label_key: :stage %>
162
+ ```
163
+
164
+ Options: `label_key`.
165
+
166
+ ### Combined Charts
167
+
168
+ Layer different series types on the same chart:
169
+
170
+ ```erb
171
+ <%= trackplot_chart @data do |c| %>
172
+ <% c.bar :revenue, color: "#06b6d4", opacity: 0.6 %>
173
+ <% c.line :profit, color: "#6366f1", curve: true %>
174
+ <% c.axis :x, data_key: :month %>
175
+ <% c.axis :y %>
176
+ <% c.tooltip %>
177
+ <% c.legend %>
178
+ <% c.grid %>
179
+ <% end %>
180
+ ```
181
+
182
+ ## Components
183
+
184
+ ### Axis
185
+
186
+ ```erb
187
+ <% c.axis :x, data_key: :month %>
188
+ <% c.axis :y, label: "Revenue ($)", format: :currency, tick_count: 5 %>
189
+ ```
190
+
191
+ Options: `data_key`, `label`, `format`, `tick_count`, `tick_rotation`.
192
+
193
+ ### Tooltip
194
+
195
+ ```erb
196
+ <% c.tooltip format: :currency %>
197
+ ```
198
+
199
+ Options: `format`, `label_format`.
200
+
201
+ ### Legend
202
+
203
+ ```erb
204
+ <% c.legend position: :top %>
205
+ ```
206
+
207
+ Options: `position` (`:top` or `:bottom`), `clickable`.
208
+
209
+ ### Grid
210
+
211
+ ```erb
212
+ <% c.grid horizontal: true, vertical: true %>
213
+ ```
214
+
215
+ Options: `horizontal` (default true), `vertical`.
216
+
217
+ ### Reference Line
218
+
219
+ Draw horizontal or vertical lines for targets, thresholds, or annotations:
220
+
221
+ ```erb
222
+ <% c.reference_line y: 5000, label: "Target", color: "#ef4444" %>
223
+ <% c.reference_line x: "Mar", label: "Launch", color: "#6366f1", dashed: false %>
224
+ ```
225
+
226
+ Options: `y` or `x` (value), `label`, `color`, `dashed` (default true), `stroke_width`.
227
+
228
+ ## Number Formatting
229
+
230
+ Both axes and tooltips accept format presets or raw D3 format strings:
231
+
232
+ | Preset | Output | Example |
233
+ |--------|--------|---------|
234
+ | `:currency` | `$1,234` | `format: :currency` |
235
+ | `:percent` | `42%` | `format: :percent` |
236
+ | `:compact` | `1.2k` | `format: :compact` |
237
+ | `:decimal` | `1,234.56` | `format: :decimal` |
238
+ | `:integer` | `1,234` | `format: :integer` |
239
+
240
+ Or pass a raw D3 format string: `format: "$,.2f"`.
241
+
242
+ ## Theming
243
+
244
+ Four built-in themes, plus fully custom themes via Hash:
245
+
246
+ ```erb
247
+ <%= trackplot_chart @data, theme: :dark do |c| %>
248
+ ...
249
+ <% end %>
250
+ ```
251
+
252
+ Available presets: `:default`, `:dark`, `:vibrant`, `:minimal`.
253
+
254
+ Custom theme (merges with defaults):
255
+
256
+ ```erb
257
+ <%= trackplot_chart @data, theme: { colors: ["#ff0000", "#00ff00"], background: "#111" } do |c| %>
258
+ ...
259
+ <% end %>
260
+ ```
261
+
262
+ Theme properties: `colors`, `background`, `text_color`, `axis_color`, `grid_color`, `tooltip_bg`, `tooltip_text`, `tooltip_border`, `font`.
263
+
264
+ ## Click Events
265
+
266
+ Every interactive element (bars, dots, pie slices, funnel stages...) dispatches a `trackplot:click` CustomEvent that bubbles up the DOM:
267
+
268
+ ```javascript
269
+ document.addEventListener("trackplot:click", function(e) {
270
+ console.log(e.detail)
271
+ // => { chartType: "bar", dataKey: "revenue", datum: {...}, index: 2, value: 4200 }
272
+ })
273
+ ```
274
+
275
+ Works great with Stimulus:
276
+
277
+ ```html
278
+ <div data-controller="chart" data-action="trackplot:click->chart#onClick">
279
+ <%= trackplot_chart @data do |c| %>
280
+ ...
281
+ <% end %>
282
+ </div>
283
+ ```
284
+
285
+ ## Turbo Support
286
+
287
+ Trackplot is built for Turbo. Charts clean up before Turbo caches pages, survive morphing, and re-render cleanly on Turbo Stream updates.
288
+
289
+ ### Stable IDs for Turbo Streams
290
+
291
+ Pass `id:` so `turbo_stream.replace` can target your chart:
292
+
293
+ ```erb
294
+ <%= trackplot_chart @data, id: "revenue-chart" do |c| %>
295
+ <% c.line :revenue, curve: true %>
296
+ <% c.axis :x, data_key: :month %>
297
+ <% c.axis :y %>
298
+ <% end %>
299
+ ```
300
+
301
+ Then push updates from your server:
302
+
303
+ ```erb
304
+ <%= turbo_stream.replace "revenue-chart" do %>
305
+ <%= trackplot_chart @fresh_data, id: "revenue-chart" do |c| %>
306
+ <% c.line :revenue, curve: true %>
307
+ <% c.axis :x, data_key: :month %>
308
+ <% c.axis :y %>
309
+ <% end %>
310
+ <% end %>
311
+ ```
312
+
313
+ ### Programmatic Data Updates
314
+
315
+ Update chart data from JavaScript (e.g., from a Stimulus controller receiving ActionCable broadcasts):
316
+
317
+ ```javascript
318
+ const chart = document.getElementById("revenue-chart")
319
+ chart.updateData(newDataArray)
320
+ ```
321
+
322
+ The `trackplot:render` event fires after every render:
323
+
324
+ ```javascript
325
+ document.addEventListener("trackplot:render", function(e) {
326
+ console.log("Chart ready:", e.target.id)
327
+ })
328
+ ```
329
+
330
+ ## Chart Options
331
+
332
+ Pass options directly to `trackplot_chart`:
333
+
334
+ | Option | Default | Description |
335
+ |--------|---------|-------------|
336
+ | `id:` | auto-generated | Stable DOM id for Turbo targeting |
337
+ | `width:` | `"100%"` | CSS width |
338
+ | `height:` | `"400px"` | CSS height |
339
+ | `animate:` | `true` | Entry animations |
340
+ | `theme:` | `:default` | Theme preset or custom Hash |
341
+ | `class:` | `nil` | Additional CSS classes |
342
+
343
+ ## Development
344
+
345
+ Run the test suite:
346
+
347
+ ```bash
348
+ ruby -Ilib -Itest -e "Dir['test/**/*_test.rb'].each { |f| require File.expand_path(f) }"
349
+ ```
350
+
351
+ Boot the demo app:
352
+
353
+ ```bash
354
+ cd test/dummy && bin/rails server
355
+ ```
356
+
357
+ ## License
358
+
359
+ MIT License. See [LICENSE.txt](LICENSE.txt).
360
+
361
+ ---
362
+
363
+ *Made️ by [eagerworks](https://eagerworks.com)*