From c8dec1d9f09743b8ee8d48866ca3eba5501dba70 Mon Sep 17 00:00:00 2001 From: Andy Sellick Date: Tue, 15 Oct 2024 15:02:22 +0100 Subject: [PATCH] Further improvements - clean up, reorder and remove redundant code - fix table vertical option - add heading element - minimise and simplify component options - add option for a chart overview description - add option to hide legend - remove unnecessary use of govspeak to wrap a visually hidden element - remove unneed styles - add tests, expand and clean up documentation --- .../components/_chart.scss | 17 -- .../components/_chart.html.erb | 105 ++++------ .../components/docs/chart.yml | 193 +++++++++--------- config/locales/en.yml | 2 +- spec/components/chart_spec.rb | 32 ++- 5 files changed, 164 insertions(+), 185 deletions(-) diff --git a/app/assets/stylesheets/govuk_publishing_components/components/_chart.scss b/app/assets/stylesheets/govuk_publishing_components/components/_chart.scss index c414cafaea..110bef2384 100644 --- a/app/assets/stylesheets/govuk_publishing_components/components/_chart.scss +++ b/app/assets/stylesheets/govuk_publishing_components/components/_chart.scss @@ -24,23 +24,6 @@ @include govuk-visually-hidden; } -// This breaks our BEM markup but is injected by the charting library and can't be avoided -// stylelint-disable selector-max-id -.gem-c-chart { - @include govuk-media-query($from: mobile) { - #chart-1, - #chart-2, - #chart-3, - #chart-4, - #chart-5, - #chart-6, - #chart-7 { - height: 400px; - } - } -} -// stylelint-enable selector-max-id - // stylelint-disable declaration-no-important .google-visualization-tooltip { background-color: #000000 !important; diff --git a/app/views/govuk_publishing_components/components/_chart.html.erb b/app/views/govuk_publishing_components/components/_chart.html.erb index f1b97d4467..0574d7fdec 100644 --- a/app/views/govuk_publishing_components/components/_chart.html.erb +++ b/app/views/govuk_publishing_components/components/_chart.html.erb @@ -2,77 +2,50 @@ add_gem_component_stylesheet("chart") add_gem_component_stylesheet("table") add_gem_component_stylesheet("details") - require "chartkick" + add_gem_component_stylesheet("heading") - chart_id ||= false - chart_label ||= "data" - chart_width ||= "90%" - table_id ||= false + chart_heading ||= nil + chart_heading_level ||= 2 table_direction ||= "horizontal" - chart_title ||= nil h_axis_title ||= nil v_axis_title ||= nil - from ||= false - to ||= false - percent_metric ||= false rows ||= [] keys ||= [] + chart_overview ||= nil + hide_legend ||= false - # http://strftime.org/ - Date::DATE_FORMATS[:table_format] = '%-d %b %Y' - - # https://developers.google.com/chart/interactive/docs/reference#dateformatter - chart_date_format = 'd MMM Y' - - if percent_metric - maximum_y = 100 - elsif rows.any? - row_maximums = rows.map { |row| row[:values].compact.max } - overall_maximum = row_maximums.max + chart_id = "chart-id-#{SecureRandom.hex(4)}" + table_id = "table-id-#{SecureRandom.hex(4)}" - if overall_maximum == 0 - # set max value to 3 if data is all 0 avoid negative numbers on Y axis - maximum_y = 3 - elsif overall_maximum < 10 - # for low numbers let line hit top to avoid a fractional max value - maximum_y = overall_maximum - else - # for higher numbers give breathing space to line - maximum_y = overall_maximum * 1.3 - - if overall_maximum > 99999 - chart_width = "80%" - end - end - end - - Chartkick.options[:html] = '
' + require "chartkick" + Chartkick.options[:html] = '
' # config options are here: https://developers.google.com/chart/interactive/docs/gallery/linechart + font_16 = { color: '#000', fontName: 'GDS Transport', fontSize: '16', italic: false } + font_19 = { color: '#000', fontName: 'GDS Transport', fontSize: '19', italic: false } + legend = 'none' + legend = { position: 'top', textStyle: font_16 } unless hide_legend + chart_library_options = { - title: chart_title, - legend: { - position: 'bottom', - textStyle: { color: '#000', fontName: 'GDS Transport', fontSize: '16' }, - }, - chartArea: { width: chart_width, height: '70%' }, - curveType: 'none', + chartArea: { width: '80%', height: '60%' }, tooltip: { showColorCode: true, isHtml: true, trigger: 'both'}, crosshair: { orientation: 'vertical', trigger: 'both', color: '#ccc' }, - loading: "Loading...", + legend: legend, + pointSize: 10, + height: 400, hAxis: { - viewWindow: { min: from, max: to }, - textStyle: { color: '#000', fontName: 'GDS Transport', fontSize: '16' }, - format: chart_date_format, - title: h_axis_title + textStyle: font_16, + format: 'd MMM Y', # https://developers.google.com/chart/interactive/docs/reference#dateformatter + title: h_axis_title, + titleTextStyle: font_19, }, vAxis: { - viewWindow: { min: 0, max: maximum_y }, format: '#,###,###', - textStyle: { color: '#000', fontName: 'GDS Transport', fontSize: '16' }, - title: v_axis_title + textStyle: font_16, + title: v_axis_title, + titleTextStyle: font_19, }, - pointSize: 10, } + if rows.length > 0 && keys.length > 0 chart_format_data = rows.map do |row| { @@ -83,22 +56,28 @@ end end %> -<% if rows.length > 0 && keys.length > 0 && chart_id && table_id %> +<% if rows.length > 0 && keys.length > 0 %> <%= javascript_include_tag "https://www.gstatic.com/charts/loader.js" %>
+ <% if chart_heading %> + <%= render "govuk_publishing_components/components/heading", { + text: chart_heading, + heading_level: chart_heading_level, + margin_bottom: 2, + } %> + <% end %> +
- <%= render "govuk_publishing_components/components/govspeak" do %> -
- The chart is a visual representation of the data available - in the table. -
- <% end %> +
+ This chart is a visual representation of the data available in the table. + <%= content_tag :span, chart_overview, class: "gem-c-chart__overview" if chart_overview %> +
<%= line_chart(chart_format_data, library: chart_library_options) %>
+
- <%= render( - "govuk_publishing_components/components/details", - title: t("components.chart.table_dropdown", metric_name: chart_label) + <%= render("govuk_publishing_components/components/details", + title: t("components.chart.table_dropdown") ) do %>
diff --git a/app/views/govuk_publishing_components/components/docs/chart.yml b/app/views/govuk_publishing_components/components/docs/chart.yml index 006e2876c3..e876f765a5 100644 --- a/app/views/govuk_publishing_components/components/docs/chart.yml +++ b/app/views/govuk_publishing_components/components/docs/chart.yml @@ -2,18 +2,15 @@ name: "Chart" description: "The chart component presents a data chart and a tabular version of the same data" part_of_admin_layout: true body: | - This component takes a single set of data and presents it in a line graph and a table with one or more rows and lines. - At mobile width the two are presented sequentially, and on wider screens they are presented in tabs the user can switch - between. The chart relies chartkick and renders using javascript, so the table is provided as a fallback for a lack of javascript, + This component takes a set of data and presents it as a line graph and a table with one or more rows and lines. + The chart relies upon chartkick and renders using JavaScript, so the table is provided as a fallback for a lack of JavaScript, an accessible view on the data for screenreaders, and a simple view of the raw data for all users. + The `overview` option can be used to provide a explanation for screen reader users of what the graph shows. + accessibility_criteria: | - - Tabs must: - - have meaningful titles - - follow the link accessibility criteria - - Tab contents must - - have meaningful captions - - Charts must: + Charts must: + - use line colours with a contrast ratio higher than 4.5:1 against the background colour to meet WCAG AA shared_accessibility_criteria: @@ -22,78 +19,55 @@ shared_accessibility_criteria: examples: default: data: - caption: 'Unique page views in February' - h_axis_title: "Day" - v_axis_title: "Views" - chart_id: 'pviews_chart' - table_id: 'pviews_table' - chart_title: 'Page views chart' - table_title: 'Page views table' + chart_heading: Page views chart + h_axis_title: Day + v_axis_title: Views + overview: This chart shows page views for January 2015. + hide_legend: true keys: - - "1st" - - "2nd" - - "3rd" - - "4th" - - "5th" - - "6th" - - "7th" - - "8th" - - "9th" - - "10th" - - "11th" - - "12th" - - "13th" - - "14th" - - "15th" - - "16th" - - "17th" - - "18th" - - "19th" + - "2015-01-01" + - "2015-01-02" + - "2015-01-03" + - "2015-01-04" + - "2015-01-05" + - "2015-01-06" + - "2015-01-07" + - "2015-01-08" + - "2015-01-09" + - "2015-01-10" rows: - - label: "January 2015" + - label: January 2015 values: - - 5 - - 119 - - 74 - - 82 - - 27 - - 45 - - 11 - - 21 - - 67 - - 43 - - 74 - - 92 - - 91 - - 67 - - 55 - - 81 - - 103 - - 62 - - 40 + - 500 + - 1190 + - 740 + - 820 + - 270 + - 450 + - 110 + - 210 + - 670 + - 430 multiple rows of data: + description: Where more than one series is shown on a chart, do not hide the legend. data: - caption: 'Unique page views in February' - h_axis_title: "Day" - v_axis_title: "Views" - chart_id: 'second_pviews_chart' - table_id: 'second_pviews_table' - chart_title: 'Page views chart' - table_title: 'Page views table' + chart_heading: Page views chart + h_axis_title: Day + v_axis_title: Views keys: - - "1st" - - "2nd" - - "3rd" - - "4th" - - "5th" - - "6th" - - "7th" - - "8th" - - "9th" - - "10th" + - 1st + - 2nd + - 3rd + - 4th + - 5th + - 6th + - 7th + - 8th + - 9th + - 10th rows: - - label: "January 2015" + - label: January 2015 values: - 5 - 119 @@ -105,7 +79,7 @@ examples: - 21 - 67 - 43 - - label: "January 2016" + - label: January 2016 values: - 5 - 8 @@ -117,7 +91,7 @@ examples: - 61 - 14 - 91 - - label: "January 2017" + - label: January 2017 values: - 31 - 81 @@ -125,31 +99,62 @@ examples: - 15 - 52 - 61 - - 32 + - 143 - 27 - 18 - 34 - horizontal table: + vertical table: + description: Reorient the table to better suit the output of some data sets. + data: + chart_heading: Page views chart + table_direction: vertical + h_axis_title: Day + v_axis_title: Views + keys: + - 1st + - 2nd + - 3rd + - 4th + - 5th + - 6th + - 7th + rows: + - label: January 2015 + values: + - 5 + - 119 + - 74 + - 117 + - 33 + - 89 + - 79 + - label: January 2016 + values: + - 3 + - 8 + - 37 + - 82 + - 118 + - 85 + - 80 + with_a_different_heading_level: + description: Use a different heading level for the chart heading. It defaults to a H2. data: - caption: 'Unique page views in February' - table_direction: "horizontal" - h_axis_title: "Day" - v_axis_title: "Views" - chart_id: 'third_pviews_chart' - table_id: 'third_pviews_table' - chart_title: 'Page views chart' - table_title: 'Page views table' + chart_heading: Page views chart + chart_heading_level: 4 + h_axis_title: Day + v_axis_title: Views keys: - - "1st" - - "2nd" - - "3rd" - - "4th" - - "5th" - - "6th" - - "7th" + - 1st + - 2nd + - 3rd + - 4th + - 5th + - 6th + - 7th rows: - - label: "January 2015" + - label: January 2015 values: - 5 - 119 @@ -158,7 +163,7 @@ examples: - 33 - 89 - 79 - - label: "January 2016" + - label: January 2016 values: - 3 - 8 diff --git a/config/locales/en.yml b/config/locales/en.yml index 47b5c09a5f..317fa61ff2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -33,7 +33,7 @@ en: characters: characters words: words chart: - table_dropdown: '%{metric_name} table' + table_dropdown: Data table chat_entry: heading: Try GOV.UK Chat description: Sign up to GOV.UK’s experimental new AI tool and find answers to your business questions diff --git a/spec/components/chart_spec.rb b/spec/components/chart_spec.rb index db8a68ed13..3386cec8cd 100644 --- a/spec/components/chart_spec.rb +++ b/spec/components/chart_spec.rb @@ -7,11 +7,8 @@ def component_name let(:data) do { - caption: "Unique page views", chart_label: "Page views chart", table_label: "Page views table", - chart_id: "pviews_jan_chart", - table_id: "pviews_jan_table", keys: (Date.new(2017, 12, 1)..Date.new(2017, 12, 12)).to_a, rows: [ { @@ -40,13 +37,6 @@ def component_name assert_empty render_component(data) end - it "does not render if tab data is missing" do - data[:chart_id] = false - assert_empty render_component(data) - data[:table_id] = false - assert_empty render_component(data) - end - it "renders when given valid data" do render_component(data) assert_select ".gem-c-chart", 1 @@ -76,4 +66,26 @@ def component_name render_component(data) assert_select "script", text: /new Chartkick.["LineChart"]/ end + + it "displays a heading" do + data[:chart_heading] = "hello" + render_component(data) + + assert_select "h2.gem-c-heading", text: "hello" + end + + it "displays a heading with a custom heading level" do + data[:chart_heading] = "hello" + data[:chart_heading_level] = 4 + render_component(data) + + assert_select "h4.gem-c-heading", text: "hello" + end + + it "can include an overview" do + text = "This chart shows a gradual decline in the numbers of hedgehogs using social media since 2008." + data[:chart_overview] = text + render_component(data) + assert_select ".gem-c-chart__overview", text: + end end