Revision history for HTML-D3 - Visualise various charts using D3
0.19 Tue Oct 13 03:35:05 PM EDT 2026
[ Enhancements ]
- render_stacked_bar_snippet: new snippet method that generates an embeddable
D3 v7 stacked bar chart. Accepts an arrayref of hashrefs (one row per
category/segment combination) and an optional \%opts hashref. Opts: cat_col,
seg_col, val_col (row-hash key names, defaults 'cat'/'seg'/'val'), orient
('v' vertical / 'h' horizontal, default 'v'), scheme (D3 categorical colour
scheme: tableau10/category10/set2/set3/paired, default 'tableau10'), x_label
(axis label, default ''), sort (undef / 'value' desc-total / 'label' alpha).
Multiple rows sharing the same cat+seg are summed on the Perl side before
encoding. Uses d3.stack() with d3.stackOrderNone / d3.stackOffsetNone.
Includes an interactive legend: clicking a segment label toggles that layer
on/off and re-stacks the visible segments. Tooltip shows category, segment,
and value on mouseover. Returns { svg_id => 'stacked_bar', html => Str }.
- render_combo_snippet: new snippet method that generates an embeddable combo
chart — bars for one measure on the left Y axis, a line for another on the
right Y axis, sharing the same X (category/band) axis. Accepts an arrayref
of hashrefs and \%opts: x_col, bar_col, line_col (row-hash key names,
defaults 'x'/'bar_val'/'line_val'), bar_label, line_label (legend/axis
labels, defaults 'Bar'/'Line'), bar_color (default 'steelblue'), line_color
(default '#e15759'). Two independent d3.scaleLinear domains (left for bars,
right for line); bars rendered first, line path and dots on top. Both axes
labelled. Tooltip on bar and dot mouseover shows all three measures.
Returns { svg_id => 'combo_chart', html => Str }.
- render_treemap_snippet: new snippet method that generates an embeddable D3
v7 treemap using d3.treemapSquarify tiling. Accepts two data formats:
(1) flat-path arrayref of hashrefs [{path => 'Root/A/X', value => N}, ...]
converted to a stratify hierarchy via d3.stratify() inside the generated JS;
(2) a nested hashref tree with name/children/value structure passed directly
to d3.hierarchy(). Format is detected by ref() of the first argument.
\%opts: path_sep (separator string for flat paths, default '/'), scheme
(categorical colour scheme, default 'tableau10'), label (bool, default 1;
shows node name inside each cell, clipped to cell width). Tooltip shows node
name and value. Returns { svg_id => 'treemap', html => Str }.
- render_histogram_snippet: new snippet method that generates an embeddable
frequency histogram. Accepts an arrayref of numeric scalars (pre-extracted
by the caller — no column-extraction logic inside the module) and \%opts:
bins (positive integer, default 20; pass undef for automatic Sturges count:
ceil(log2(n)+1)), x_label (axis label, default ''), color (bar fill colour,
default 'steelblue'). Uses d3.bin() with xScale.ticks(numBins) thresholds.
Tooltip shows bin range and count on mouseover.
Returns { svg_id => 'histogram', html => Str }.
0.18 Wed Sep 23 11:10:09 AM EDT 2026
[ Enhancements ]
- render_bar_chart_snippet: new snippet method that generates an embeddable
D3 v7 bar chart. Accepts an array of [$label, $value] (or
[$label, $value, \%extra]) pairs and an optional \%opts hashref with keys:
orientation ('vertical'/'horizontal', default 'vertical'),
sort_bars ('value'/'label'/'none', default 'none'),
max_bars (int, default 0; collapses tail into "Other"),
color (CSS colour or 'categorical' for Tableau-10 palette, default
'steelblue'), show_values (bool, default 0; prints values on bars),
animated (bool, default 0; bars grow from baseline with 800 ms stagger;
respects prefers-reduced-motion), value_label (tooltip label, default
'Value'), x_label (bottom-axis label, default ''). Returns
{ svg_id => 'bar_chart', html => Str }. Negative values are silently
converted to their absolute value; undef values are silently skipped.
X-axis labels are rotated -45 degrees when more than 8 bars are shown in
vertical orientation. Extra \%extra fields appear as additional tooltip
rows. Returns a Perl character string (UTF-8 flag set).
- render_scatter_chart_snippet: new snippet method that generates an
embeddable D3 v7 scatter chart. Accepts an array of [$x, $y] (or
[$x, $y, \%extra]) pairs; both x and y must be numeric. Optional \%opts:
id (default 'scatter_chart'), color (CSS colour, default 'steelblue'),
x_label, y_label, value_label (tooltip label, default 'Value'), animated
(bool; circles fade in from opacity 0; respects prefers-reduced-motion),
responsive. Returns { svg_id => Str, html => Str }. Uses d3.scaleLinear
for both axes; includes esc() XSS helper in generated JavaScript.
- render_table_snippet: new snippet method that generates an embeddable HTML
table with optional D3-powered column sorting. Accepts an array of array
references; the first row is the header. Optional \%opts: id (default
'data_table'), sortable (bool, default 1; adds clickable column headers
with D3 sort), caption (string; emits a <caption> element). Returns
{ table_id => Str, html => Str } (note: table_id, not svg_id). All header
and cell content is HTML-escaped.
- id opt: all five existing snippet methods (render_line_chart_snippet,
render_zoomable_line_chart_snippet, render_pie_chart_snippet,
render_heatmap_snippet, render_bar_chart_snippet) now accept an id key in
\%opts that overrides the default svg_id. The returned svg_id reflects the
override. Derived element ids (tooltip div, legend div, etc.) are computed
from the svg_id string. Fully backward-compatible: omitting id gives the
same default id as before.
- responsive opt: all render methods now support a responsive display mode.
Pass responsive => 1 to the constructor to make all full-page renders emit
viewBox="0 0 W H" width="100%" height="auto" instead of fixed pixel
dimensions on the SVG element. Snippet methods additionally accept
responsive in their per-call \%opts (takes precedence over the constructor
setting). Default is 0 (fixed dimensions), so existing callers are
unaffected. Uses new private helper _svg_attrs().
[ Bug Fixes ]
- render_pie_chart_snippet: tooltip handler was missing HTML sanitisation.
Added esc() JavaScript helper (same as bar/heatmap/scatter snippets) and
applied it to slice labels and extra-field keys and values in the
mouseover handler. Prevents XSS when label or extra fields contain HTML
special characters.
- render_line_chart_snippet: completed API documentation (Arguments, Options,
Return value, Errors, Side effects, API SPECIFICATION). Now accepts an
optional second argument \%opts with id and responsive keys.
0.17 Tue Sep 22 08:45:56 PM EDT 2026
[ Bug Fixes ]
- All render_*_snippet methods now return a Perl character string (UTF-8
flag set) in the {html} value instead of a UTF-8 byte string. The
previous use of encode_json() produced octets; any caller that
concatenated the result with a character string (e.g. a Mojolicious
Template Toolkit response) would silently double-encode non-ASCII
characters, producing mojibake. Fixed by replacing encode_json() with
a module-level JSON::MaybeXS instance configured with utf8 => 0, which
serialises to a character string.
0.16 Mon Sep 21 07:34:35 PM EDT 2026
[ Enhancements ]
- render_heatmap_snippet: new snippet method that generates an embeddable
D3 v7 grid heatmap. Accepts an array of [$x, $y, $value] triples and an
optional \%opts hashref with keys: color_scheme (YlOrRd/Blues/Greens/
Purples/RdPu/YlGnBu, default YlOrRd), x_label, y_label, val_label
(tooltip label, default 'Value'), show_values (print value in each cell,
auto-suppressed when cell < 28px), cell_padding (0-8 px gap, default 2),
legend (colour-scale bar, default on), animated (fade-in with
prefers-reduced-motion support, default off). Returns
{ svg_id => 'heatmap', html => Str }. undef values are silently skipped;
duplicate (x, y) pairs: last write wins. Requires Scalar::Util
looks_like_number (already in core distribution).
0.15 Wed Sep 16 01:51:38 PM EDT 2026
[ Enhancements ]
- render_pie_chart, render_animated_pie_chart, render_pie_chart_snippet: new
optional C<separator> key in the C<%opts> second argument controls the
character shown between label and value in the legend (default C<'/'>).
render_pie_chart and render_animated_pie_chart now accept the optional
second hashref argument for the first time; existing callers passing only
C<$data> are unaffected.
0.14 Tue Sep 15 09:12:17 PM EDT 2026
[ Enhancements ]
- render_pie_chart_snippet: major upgrade. Now accepts an optional second
argument \%opts with six keys:
- animated (bool, default 0): fan slices in from arc-length 0 using
attrTween / d3.easeBackOut.overshoot(1.2) with 800 ms staggered
transitions; legend fades in after; respects prefers-reduced-motion
- donut (bool, default 0): inner radius 38% of outer; total sum shown
in the centre hole
- sort_slices ('value'|'label'|'none', default 'none'): sort order
- max_slices (int, default 0): collapse tail into an "Other" slice
- legend (bool, default 1): HTML legend panel with colour swatches
- color_scheme (string, default 'tableau10'): supports tableau10,
category10, set2, set3, paired
Negative values are silently converted to their absolute value; zero-
value slices are silently omitted. Optional \%extra hashref per data
point is shown as additional rows in the hover tooltip.
svg_id changes from 'chart' to 'pie_chart' for namespace clarity.
(Breaking change in svg_id value; all other behaviour is backward-
compatible when opts are omitted.)
0.13 Tue Sep 15 06:05:45 PM EDT 2026
[ Enhancements ]
- render_zoomable_line_chart_snippet: accept an optional second argument
{ animated => 1 } to animate the initial line draw on page load.
The line traces itself left-to-right via stroke-dashoffset / d3.easeLinear
(1200 ms); data-point circles then fade in from opacity 0 over 300 ms
(after a 1200 ms delay so they appear only once the line reaches them).
Subsequent zoom and reset redraws are never animated.
Respects prefers-reduced-motion: when the user has requested reduced
motion the chart draws immediately at full opacity.
Omitting the second argument or passing { animated => 0 } gives the
existing behaviour unchanged (backward-compatible).
0.12 Sun Sep 13 08:14:05 AM EDT 2026
[ Enhancements ]
- Added render_animated_bar_chart(): bar chart with on-load grow animation —
each bar rises from the baseline using d3.transition() with an 800 ms
duration and a 100 ms per-bar stagger, so bars appear one after another
from left to right
- Added render_animated_line_chart(): line chart with on-load draw animation —
the line traces itself left-to-right via the stroke-dashoffset technique with
d3.easeLinear (1500 ms), followed by data-point circles fading in from
opacity 0 once the line is complete
- Added render_pie_chart(): full-page pie chart with percentage labels inside
each slice and a colour legend; slices coloured with d3.schemeCategory10
- Added render_animated_pie_chart(): same as render_pie_chart() but slices fan
out from zero on page load via attrTween/d3.interpolate (1000 ms), with
percentage labels fading in once drawing is complete
- Added render_pie_chart_snippet(): embeddable pie chart fragment returning
{svg_id, html} — no page shell, no D3 CDN tag; caller loads D3
[ Tests ]
- Test::HTML::T5 doesn't build on a number of platforms, so
remove the dependancy. Hopefully this will be fixed at sometime.
0.11 Thu Sep 10 09:32:08 PM EDT 2026
[ Bug Fixes ]
- render_zoomable_line_chart_snippet: the y-axis lower bound was
hard-coded to 0, causing data points with negative Y values to be
plotted off-screen below the x-axis. Changed to
Math.min(0, d3.min(newData, d => d.value)) so the domain extends
downward when the data contains negative values (e.g.
accounting-notation amounts).
0.10 Fri Aug 28 08:57:09 PM EDT 2026
[ Enhancements ]
- Added render_zoomable_line_chart_snippet(): embeddable line chart with brush-to-zoom — drag to select an x-axis range, animated transition to the zoomed view, incremental re-zoom on the zoomed view, and a Reset zoom button to restore the full dataset
0.09 Thu Aug 27 09:16:02 PM EDT 2026
[ Enhancements ]
- render_line_chart_snippet: accept an optional third element per data pair — a hashref of extra key/value pairs serialised as an "extra" property in the D3 data binding and appended as additional rows in the mouseover tooltip
0.08 Thu Aug 27 01:30:10 PM EDT 2026
[ Enhancements ]
- Use Params::Get
- Added test dashboard
- Added support for Object::Configure
- Added render_line_chart_snippet() returning an embeddable {svg_id, html} fragment for use in Mojolicious TT (and similar) layouts without post-processing
[ Bug Fixes ]
- Escape </b> as <\/b> in all JavaScript tooltip .html() strings to fix html-tidy '<' + '/' + letter failures on cpantesters
https://www.cpantesters.org/cpan/report/8321add6-d178-11ef-8e88-00fe6d8775ea
0.07 Fri Jan 10 21:16:49 EST 2025
Added support for interactive legends
0.06 Thu Jan 9 21:51:36 EST 2025
Added support for legends
0.05 Wed Jan 8 21:04:21 EST 2025
Added support for animated tooltips
0.04 Tue Jan 7 21:26:42 EST 2025
Added support for line charts with tooltips
Added support for multiple line charts with tooltips
0.03 Mon Jan 6 20:55:12 EST 2025
Added line chart support
Use JSON::MaybeXS instead of JSON
0.02 Mon Jan 6 10:13:11 EST 2025
Fix CI breakage
0.01 Mon Jan 6 09:47:22 EST 2025
First draft - POC: generates bar charts only
Keyboard Shortcuts
Global
s
Focus search bar
?
Bring up this help dialog
GitHub
gp
Go to pull requests
gi
Go to GitHub issues (only if GitHub is preferred repository)