@@ -21,14 +21,16 @@ That's it. No JavaScript files to write, no chart config objects to manage, no b
2121
2222---
2323
24- ## 10 Chart Types
24+ ## Chart Types
25+
26+ | Cartesian | Radial | Hierarchical | Other |
27+ | -----------| --------| --------------| -------|
28+ | Line | Pie / Donut | Treemap | Horizontal Bar |
29+ | Bar (grouped + stacked) | Radar | | Funnel |
30+ | Area (+ stacked) | | | Candlestick (OHLC) |
31+ | Scatter | | | Heatmap |
2532
26- | Cartesian | Radial | Other |
27- | -----------| --------| -------|
28- | Line | Pie / Donut | Horizontal Bar |
29- | Bar | Radar | Funnel |
30- | Area (+ stacked) | | Candlestick (OHLC) |
31- | Scatter | | |
33+ Plus ** sparklines** for inline mini-charts in tables and dashboards.
3234
3335Mix and match freely — bars + lines on the same chart just work.
3436
@@ -90,15 +92,22 @@ Your data can use symbol or string keys — Trackplot normalizes both:
9092<% c.line :revenue, color: "#6366f1", curve: true, dashed: true %>
9193```
9294
93- Options: ` color ` , ` curve ` (smooth), ` dashed ` , ` stroke_width ` , ` dot ` (true/false), ` dot_size ` .
95+ Options: ` color ` , ` curve ` (smooth), ` dashed ` , ` stroke_width ` , ` dot ` (true/false), ` dot_size ` , ` y_axis ` .
9496
9597### Bar
9698
9799``` erb
98100<% c.bar :sales, color: "#06b6d4", opacity: 0.8, radius: 6 %>
99101```
100102
101- Multiple bar series render as grouped bars automatically. Options: ` color ` , ` opacity ` , ` radius ` (corner rounding), ` stack ` (group name for stacking).
103+ Multiple bar series render as grouped bars automatically. Options: ` color ` , ` opacity ` , ` radius ` (corner rounding), ` stack ` (group name for stacking), ` y_axis ` .
104+
105+ Stack bars by giving them the same ` stack ` name:
106+
107+ ``` erb
108+ <% c.bar :revenue, stack: "main", color: "#6366f1" %>
109+ <% c.bar :costs, stack: "main", color: "#f59e0b" %>
110+ ```
102111
103112### Area
104113
@@ -119,7 +128,7 @@ Renders a gradient fill with a stroke line. Stack multiple areas by giving them
119128<% c.scatter :weight, color: "#ec4899", dot_size: 6 %>
120129```
121130
122- Options: ` color ` , ` dot_size ` , ` opacity ` , ` x_key ` (override x-axis key).
131+ Options: ` color ` , ` dot_size ` , ` opacity ` , ` x_key ` (override x-axis key), ` y_axis ` .
123132
124133### Pie / Donut
125134
@@ -163,6 +172,33 @@ Options: `up_color`, `down_color`.
163172
164173Options: ` label_key ` .
165174
175+ ### Heatmap
176+
177+ Visualize density or intensity across two dimensions:
178+
179+ ``` erb
180+ <%= trackplot_chart @activity_data, height: "300px" do |c| %>
181+ <% c.heatmap x_key: :day, y_key: :hour, value_key: :count,
182+ color_range: ["#f0f9ff", "#1e40af"] %>
183+ <% c.tooltip %>
184+ <% end %>
185+ ```
186+
187+ Options: ` x_key ` , ` y_key ` , ` value_key ` , ` color_range ` (two-color array), ` radius ` .
188+
189+ ### Treemap
190+
191+ Show hierarchical data as nested rectangles:
192+
193+ ``` erb
194+ <%= trackplot_chart @budget_data, height: "300px" do |c| %>
195+ <% c.treemap value_key: :amount, label_key: :name, parent_key: :department %>
196+ <% c.tooltip %>
197+ <% end %>
198+ ```
199+
200+ Options: ` value_key ` , ` label_key ` , ` parent_key ` (optional — groups data into a hierarchy). Without ` parent_key ` , data is treated as flat.
201+
166202### Combined Charts
167203
168204Layer different series types on the same chart:
@@ -179,6 +215,32 @@ Layer different series types on the same chart:
179215<% end %>
180216```
181217
218+ ## Sparklines
219+
220+ Inline mini-charts for tables and dashboards — no axes, no labels, just the shape:
221+
222+ ``` erb
223+ <%= trackplot_sparkline @trend_data, key: :revenue, type: :line, color: "#6366f1" %>
224+ ```
225+
226+ Types: ` :line ` (default, with last-dot indicator), ` :bar ` , ` :area ` .
227+
228+ Options: ` key: ` (required), ` type: ` , ` color: ` , ` width: ` (default ` "120px" ` ), ` height: ` (default ` "32px" ` ), ` stroke_width: ` , ` dot: ` .
229+
230+ Use them in tables:
231+
232+ ``` erb
233+ <table>
234+ <% @metrics.each do |metric| %>
235+ <tr>
236+ <td><%= metric.name %></td>
237+ <td><%= trackplot_sparkline metric.history, key: :value, color: "#10b981" %></td>
238+ <td><%= metric.current_value %></td>
239+ </tr>
240+ <% end %>
241+ </table>
242+ ```
243+
182244## Components
183245
184246### Axis
@@ -188,7 +250,23 @@ Layer different series types on the same chart:
188250<% c.axis :y, label: "Revenue ($)", format: :currency, tick_count: 5 %>
189251```
190252
191- Options: ` data_key ` , ` label ` , ` format ` , ` tick_count ` , ` tick_rotation ` .
253+ Options: ` data_key ` , ` label ` , ` format ` , ` tick_count ` , ` tick_rotation ` , ` axis_id ` .
254+
255+ ### Dual Y-Axis
256+
257+ Compare series with different scales on the same chart:
258+
259+ ``` erb
260+ <%= trackplot_chart @data do |c| %>
261+ <% c.bar :revenue, color: "#6366f1" %>
262+ <% c.line :conversion_rate, color: "#ef4444", y_axis: :right %>
263+ <% c.axis :x, data_key: :month %>
264+ <% c.axis :y, format: :currency %>
265+ <% c.axis :y, axis_id: :right, format: :percent %>
266+ <% end %>
267+ ```
268+
269+ Add ` axis_id: :right ` to a y-axis, then bind series to it with ` y_axis: :right ` . Works on line, bar, area, and scatter.
192270
193271### Tooltip
194272
@@ -225,6 +303,28 @@ Draw horizontal or vertical lines for targets, thresholds, or annotations:
225303
226304Options: ` y ` or ` x ` (value), ` label ` , ` color ` , ` dashed ` (default true), ` stroke_width ` .
227305
306+ ### Data Labels
307+
308+ Show formatted values directly on bars, dots, and pie slices:
309+
310+ ``` erb
311+ <% c.data_label format: :currency, position: :top %>
312+ ```
313+
314+ Options: ` format ` (any format preset or D3 format string), ` position ` (` :top ` , ` :center ` , ` :outside ` ), ` font_size ` (default 11).
315+
316+ ### Brush
317+
318+ Interactive range selection for exploring large datasets:
319+
320+ ``` erb
321+ <% c.brush axis: :x %>
322+ ```
323+
324+ Renders a mini preview below the chart. Drag to select a range — the chart zooms in. Double-click to reset.
325+
326+ Options: ` axis ` (default ` :x ` ), ` height ` (default 40).
327+
228328## Number Formatting
229329
230330Both axes and tooltips accept format presets or raw D3 format strings:
@@ -261,6 +361,38 @@ Custom theme (merges with defaults):
261361
262362Theme properties: ` colors ` , ` background ` , ` text_color ` , ` axis_color ` , ` grid_color ` , ` tooltip_bg ` , ` tooltip_text ` , ` tooltip_border ` , ` font ` .
263363
364+ ## Accessibility
365+
366+ Charts support ARIA attributes for screen readers:
367+
368+ ``` erb
369+ <%= trackplot_chart @data, title: "Monthly Revenue", description: "Revenue trend from Jan to Jul" do |c| %>
370+ <% c.line :revenue %>
371+ <% c.axis :x, data_key: :month %>
372+ <% c.axis :y %>
373+ <% end %>
374+ ```
375+
376+ When ` title: ` is set:
377+ - The ` <trackplot-chart> ` element gets ` role="img" ` and ` aria-label `
378+ - The SVG includes ` <title> ` and ` <desc> ` elements
379+ - Decorative elements (grid lines, crosshair) are marked ` aria-hidden="true" `
380+ - Data points get ` aria-label ` attributes with their values
381+
382+ ## Empty State
383+
384+ Charts gracefully handle empty data with a centered message:
385+
386+ ``` erb
387+ <%= trackplot_chart [], empty_message: "No sales data for this period" do |c| %>
388+ <% c.line :revenue %>
389+ <% c.axis :x, data_key: :month %>
390+ <% c.axis :y %>
391+ <% end %>
392+ ```
393+
394+ The default message is "No data available". Customize it with ` empty_message: ` .
395+
264396## Click Events
265397
266398Every interactive element (bars, dots, pie slices, funnel stages...) dispatches a ` trackplot:click ` CustomEvent that bubbles up the DOM:
@@ -282,6 +414,24 @@ Works great with Stimulus:
282414</div >
283415```
284416
417+ ## Export to PNG / SVG
418+
419+ Download charts as images from JavaScript:
420+
421+ ``` javascript
422+ const chart = document .querySelector (" trackplot-chart" )
423+
424+ // PNG (default 2x resolution)
425+ chart .exportPNG ()
426+ chart .exportPNG (3 , " revenue.png" ) // custom scale and filename
427+
428+ // SVG
429+ chart .exportSVG ()
430+ chart .exportSVG (" revenue.svg" )
431+ ```
432+
433+ Both methods return a Promise that resolves with the Blob.
434+
285435## Turbo Support
286436
287437Trackplot is built for Turbo. Charts clean up before Turbo caches pages, survive morphing, and re-render cleanly on Turbo Stream updates.
@@ -319,6 +469,20 @@ const chart = document.getElementById("revenue-chart")
319469chart .updateData (newDataArray)
320470```
321471
472+ ### Real-time Data Append
473+
474+ Push new data points without a full re-render — great for live dashboards:
475+
476+ ``` javascript
477+ const chart = document .getElementById (" live-chart" )
478+ chart .appendData (
479+ [{ time: " 12:05" , value: 42 }],
480+ { maxPoints: 50 } // sliding window
481+ )
482+ ```
483+
484+ Dispatches a ` trackplot:data-update ` event after each append.
485+
322486The ` trackplot:render ` event fires after every render:
323487
324488``` javascript
@@ -327,6 +491,35 @@ document.addEventListener("trackplot:render", function(e) {
327491})
328492```
329493
494+ ## ViewComponent / Phlex Support
495+
496+ If you use [ ViewComponent] ( https://viewcomponent.org/ ) or [ Phlex] ( https://www.phlex.fun/ ) , Trackplot provides optional integrations.
497+
498+ ### ViewComponent
499+
500+ ``` ruby
501+ # In your view
502+ render Trackplot ::Component .new (data: @data , height: " 300px" ) { |c |
503+ c.line :revenue , color: " #6366f1"
504+ c.axis :x , data_key: :month
505+ c.axis :y
506+ }
507+ ```
508+
509+ Requires ` view_component ` in your Gemfile. Trackplot loads the component class only when ViewComponent is available.
510+
511+ ### Phlex
512+
513+ ``` ruby
514+ render Trackplot ::PhlexComponent .new (data: @data , height: " 300px" ) { |c |
515+ c.line :revenue , color: " #6366f1"
516+ c.axis :x , data_key: :month
517+ c.axis :y
518+ }
519+ ```
520+
521+ Requires ` phlex ` in your Gemfile.
522+
330523## Chart Options
331524
332525Pass options directly to ` trackplot_chart ` :
@@ -339,6 +532,9 @@ Pass options directly to `trackplot_chart`:
339532| ` animate: ` | ` true ` | Entry animations |
340533| ` theme: ` | ` :default ` | Theme preset or custom Hash |
341534| ` class: ` | ` nil ` | Additional CSS classes |
535+ | ` title: ` | ` nil ` | Accessibility label (adds ARIA attributes) |
536+ | ` description: ` | ` nil ` | Accessibility description (requires ` title: ` ) |
537+ | ` empty_message: ` | ` "No data available" ` | Message shown when data is empty |
342538
343539## Development
344540
@@ -354,6 +550,8 @@ Boot the demo app:
354550cd test/dummy && bin/rails server
355551```
356552
553+ See [ CONTRIBUTING.md] ( CONTRIBUTING.md ) for development setup and contribution guidelines.
554+
357555## License
358556
359557MIT License. See [ LICENSE.txt] ( LICENSE.txt ) .
0 commit comments