D 3棒グラフにおけるアクセシビリティ


もともと投稿www.a11ywithlindsey.com .
おい、すべて!まず最初に、私はこのポストで彼らの忍耐に人々に感謝したいです.私は、私が私の最後のポストを発表したあと、非常にストレスの少ない数週を過ごしました.もちろん、私は仕事でストレスの多い締め切りの最中に非常に技術的なポストをすることを選びました.その締め切りは過去からあります、そして、私は最終的にこのポストを終えました!
私はあなたが私に次について書くために何を望むか尋ねました.多くの人々は、彼らが私にデータ視覚化のためのアクセシビリティについて話すことを要求しました.私がデータ視覚化について学んだほど多くがあるので、私はこのシリーズを作ることに決めました.
私のシリーズの最初の部分のために、私はアクセス可能なバーチャートについてあなたと話をするつもりです!

開始


私はそれに慣れているのでD 3 JavaScriptライブラリを使用するつもりです.私はインラインSVGを構築しています.SVGについての大きなことは、あなたが何をしているか知っているなら、アクセスできるバーチャートを作るのはかなり簡単です.しかし、あなたは何をやっている知っている!
以下は以下のデータセットです.
const data = [
  {
    name: 'Banana Production',
    value: 20223290811,
  },
  {
    name: 'Apple Production',
    value: 8191091088.532,
  },
  {
    name: 'Clementine Production',
    value: 1162341399.19,
  },
]
ほとんどのバーグチャートで見る問題は、データが何であるかを示すテキスト要素がないことです.彼らは、それが値であることを示している軸で視覚的なバーしか持っていません.
では、この問題は何ですか?私たちには、棒と軸のラベルのテキストがあります.ただし、スクリーンリーダーはデータセットに関連付けられた値を反映しません.
VoiceOverコマンドを使用するとき、それはラベルを読んで、それから軸刻みを読むだけです.私が読みたいのはラベルとデータ値です.
我々が欲しいものは<text> 隣の要素<rect> 視覚的な意味を持つ要素.スクリーンリーダーのために最善のことは、読みやすいコンテンツがあることを保証することです.インラインSVGは画像がマークアップになるのでアクセシビリティに最適です.それはすばらしい.しかし、あなたの棒グラフは、図形とデータを通信する場合は、画面の読者は、デフォルトでそれを読むことはありません.

電位解1


私のバーのグラフにアクセスする最初の解決策は、私はxAxis .
d3.selectAll('.tick')
  .append('text')
  .text((d, i) =>
    d3
      .format('.2s')(data[i].value)
      .replace('G', 'B')
  )
The .tick クラスはd 3軸でデフォルトで来るものです、そして、それは<g> それが伴う要素.全てを選択.tick 要素を書式化したテキスト要素を追加します.
これは画面の読者のために動作しますが、私はこれが誰にとっても最もアクセス可能なデータの可視化の経験だとは思わない.yaxisの広大な範囲は、それが視覚的なユーザーに値を理解するために挑戦する可能性があります.y軸が1600億を越えるので、データの値が何であるかは、我々のユーザーに明らかでないかもしれないと仮定するのは安全かもしれません.Y軸の範囲が0 - 10ならば異なっているかもしれません.
有する<text> 要素は、画面リーダーのユーザーのためのより良い経験ですが、我々は目撃ユーザーのためにそれを改善することができます.

可能性溶液


もう一つの解決策は伝説を含むことです.色分けされた棒グラフを持つことがcolorblindnessで最もアクセス可能でないかもしれないことに注意することは、重要です.我々がこのルートに行くならば、我々は各々のバーの間で劇的でアクセス可能な対照を確実にしなければなりません.
ここでいくつかの変更を行いました.
+ const barColors = ['#000', '#d35f5f', '#fff'];
  barGroups
    .selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
-   .attr("fill", "#d35f5f")
+   .attr('fill', (d, i) => barColors[i])
+   .attr('stroke', '#000')
    .attr('class', 'bar')
    .attr('x', d => xScale(d.name))
    .attr('y', d => yScale(d.value))
    .attr('width', xScale.bandwidth())
    .attr('height', d => height - yScale(d.value));
私はbarColors 16進色でいっぱいの配列としての変数.塗りつぶし色を選択する匿名関数を使用しました.私はまた、白いバーを表示する必要があるので、ストローク色を追加!
私もSVGを広くして、若干の伝説幅を加えました.さもなければ、伝説は切られるでしょう!
const margin = { top: 20, right: 20, bottom: 70, left: 90 };
const width = 600 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
+ const legendWidth = 300;

const svg = d3
  .select("#chart")
- .attr("width", width + margin.left + margin.right)
+ .attr("width", width + margin.left + margin.right + legendWidth)
  .attr("height", height + margin.top + margin.bottom);
しかし、まだ行われていない!我々はまだ伝説を追加する必要があります!ここで私が誤りを通して学んだことは、このコードを少しリファクタリングしなければならないということです.私はD 3初心者のビットです.何度も私はあてもなく物事を試していて、少し違ったアプローチを取る必要があると実感している.ここで必要とするのはリファクタリングです.
+ const g = barGroups
+   .selectAll('g')
+   .data(data)
+   .enter()
+   .append('g')

- barGroups
-   .selectAll("rect")
-   .data(data)
-   .enter()
-   .append("rect")
+ g.append('rect')
  .attr('fill', (d, i) => barColors[i])
  .attr('stroke', '#000')
  .attr('class', 'bar')
  .attr('x', d => xScale(d.name))
  .attr('y', d => yScale(d.value))
  .attr('width', xScale.bandwidth())
  .attr('height', d => height - yScale(d.value))
我々は、複数を持つ必要があります<rect> 同じデータにバインドされた要素.私はそのデータを<g> 代わりに、私はそれに必要な要素を追加します.私は伝説のために同じデータ結合を使いたかったので、私はそれに行きました!
だから私はいくつかの新しい追加<rect> and <text> タグは、伝説を作る!
const lineItemHeight = 30
g.append('rect')
  .attr('fill', (d, i) => barColors[i])
  .attr('stroke', '#000')
  .attr('width', 20)
  .attr('height', 20)
  .attr('x', width + margin.right)
  .attr('y', (d, i) => lineItemHeight * (i + 1))

g.append('text')
  .text(d => `${d.name} - ${d.value}`)
  .attr('x', width + margin.right + 30)
  .attr('y', (d, i) => lineItemHeight * (i + 1) + 15)
今、実際のデータとラベルを反映したテキストがあります.我々がしたい最後のものの一つは、それがうまく読むように数字をフォーマットすることです.
g.append('text')
- .text(d => `${d.name} - ${d.value}`)
+ .text(d => `${d.name} - ${d3.format(".2s")(d.value).replace("G", "B")}`)
今、凡例にタイトルを追加して、B =ビリオンと言いましょう.
const svg = d3
  .select("#chart")
  .attr("width", width + margin.left + margin.right + legendWidth)
  .attr("height", height + margin.top + margin.bottom)
  .attr('aria-labelledby', 'title');

+ svg.append('text')
+  .text('Legend')
+  .attr('x', width + margin.right + margin.left)
+  .attr('y', 20)

+ svg.append('text')
+  .text('B = billion')
+  .attr('x',width + margin.right + margin.left)
+  .attr('y', 40)
凡例のタイトルとキーが若干のスペースを取ったので、伝説アイテムのポジショニングを調節したいです.
g.append('rect')
  .attr("fill", (d, i) => barColors[i])
  .attr("stroke", "#000")
  .attr('width', 20)
  .attr('height', 20)
  .attr('x', width + margin.right)
- .attr('y', (d, i) => lineItemHeight * (i + 1))
+ .attr('y', (d, i) => lineItemHeight * (i + 1) + 30)

g.append('text')
  .text(d => `${d.name} - ${d3.format(".2s")(d.value).replace("G", "B")}`)
  .attr('x', width + margin.right + 30)
- .attr('y', (d, i) => lineItemHeight * (i + 1) + 15)
+ .attr('y', (d, i) => lineItemHeight * (i + 1) + 45)
ここで最終的な結果です!

コンテキストの追加


使用するHeather Migliorisi’s graph CodePen このポストのためのインスピレーションとして.今では、画面の読者の視覚化のテキストバージョンがあります.しかし、私は彼女のグラフにより多くの文脈を加えるアリアの彼女の素晴らしい使用に気がつきました.私は彼女がした同じ原則のいくつかを取って、D 3で彼女をこのグラフに適用するつもりです(彼女はストレートのSVGで彼女のものを書きました).
私が最初にすることは、私のSVGにタイトルを加えることです.
const svg = d3
  .select("#chart")
  .attr("width", width + margin.left + margin.right + legendWidth)
  .attr("height", height + margin.top + margin.bottom)
+ .attr('aria-labelledby', 'bar-chart-title');

+ svg.append('text')
+  .text('2018 Fruit Production')
+  .attr('id', 'bar-chart-title')
+  .attr("x", margin.left)
+  .attr("y", 250)
私は彼女の作品を通過することをお勧めAccessible SVGs なぜこれが良い練習を学ぶこと.彼女は豊富な研究を行って、私よりもSVGについてもっと知りました!
私は、彼女が棒グラフをリストのように読ませた方法が好きでした.私は、それらの各々にもそれらを加えるつもりです!また、私は追加するつもりですaria-label とのグループにlist 役割
const barGroups = svg
  .append("g")
+ .attr('role', 'list')
+ .attr('aria-label', 'bar chart')
  .attr("class", "data")
  .attr("transform", `translate(${margin.left}, 0)`);

const barColors = ["#000", "#d35f5f", "#fff"];

const g = barGroups
  .selectAll('g')
  .data(data)
  .enter()
  .append('g')
+ .attr('role', 'listitem');
ヘザーが私がここでするつもりでない何かは、加えますrole="presentation" 軸に.その理由はTwitterでこの質問を投稿して、複雑な反応を得たからです.

リンジーKopacz🐞
@ littlekopope

私は主観的な感じの質問があります.あなたがSVGグラフをつくっているならば、データポイントを別の方法で発表しているならば、軸はスクリーンリーダーに少し役に立たないでしょう?例えば、“寄付- 100 k”.それが読まれるならば、軸は冗長でありませんか?
午後12時53分- 2019年5月01日
0
18
私はスクリーン読者の冗長性について考えました、しかし、他の誰かは優れた点を持ち出しました.

クリスキッチン

必ずしもそうでない.人々は常にあなたが期待する方法でアクセシビリティツールを使用しないでください.例えば、私はADHDを持って、しばしば私の執筆を支援するためにスクリーンリーダーを使用します.ビジョンの問題はない、私は何かを私に戻ってそれを読む必要があるので、私はそれがすべて意味を知っている.😊
午後21時58分- 2019年5月01日
0
1
これは私が考えていなかった何かで、ADHDを持つ誰かとしても.それで、それで、私は軸を後でDOMに入れて、Aを加えたことに決めましたaria-label SVGのそれらのグループに.
svg
  .append("g")
  .attr("class", "x-axis")
+ .attr('aria-label', 'x axis')
  .attr("transform", `translate(${margin.left}, ${height})`)
  .call(xAxis);

svg
  .append("g")
  .attr("class", "y-axis")
+ .attr('aria-label', 'y axis')
  .attr("transform", `translate(${margin.left}, 0)`)
  .call(yAxis);

結論


私は、この視覚化を大いに改善することができました!私はまだSVGに比較的新しいです、そして、これのいくつかは主観的です.軸点が冗長であるかどうかは不明です.私は、スクリーンリーダーからそれを隠すべきかどうかについて、混ざり合った答えを得ました.私はより多くのコンテキストで行くことを決めた、それが迷惑でない限り、より良いです.
あなたはどう思いますか.私に知らせてください!また、私は今patreon ! あなたが私の仕事が好きなら、後援者になることを考えてください.あなたが\5ドル誓約またはより高いならば、あなたは将来のブログ記事に投票することができます!乾杯!良い一週間を!