如何为Angular Plotly树形图添加可访问性与键盘导航?
为Angular Plotly树形图实现无障碍访问与键盘导航
由于Plotly官方暂无计划为树形图添加原生无障碍支持,可通过以下几种方案手动实现:
方案一:添加自定义无障碍覆盖层
在Plotly图表上方叠加透明的可聚焦DOM层,模拟树形图节点结构,实现键盘导航与屏幕阅读器支持:
步骤1:修改模板
在plotly-plot组件外包裹容器,新增无障碍覆盖层:
<div class="treemap-container" role="region" aria-label="树形图数据展示"> <plotly-plot [data]="[graph.data]" [layout]="graph.layout" (afterPlot)="setupAccessibilityLayer()" ></plotly-plot> <!-- 无障碍覆盖层 --> <div class="accessibility-overlay" #overlay aria-hidden="false"></div> </div>
步骤2:添加样式
确保覆盖层与图表完全重合且不干扰原有交互:
.treemap-container { position: relative; display: inline-block; } .accessibility-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .accessible-node { position: absolute; border: 1px solid transparent; tabindex: 0; pointer-events: auto; border-radius: 4px; } .accessible-node:focus { outline: 2px solid #005fcc; outline-offset: 2px; }
步骤3:生成无障碍节点
在TS中通过Plotly API获取节点坐标,创建对应可访问DOM元素:
import { Component, ViewChild, ElementRef } from '@angular/core'; import * as Plotly from 'plotly.js-dist-min'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'plotly-treemap-a11y'; @ViewChild('overlay') overlay!: ElementRef; public graph = { data: { type: "treemap", labels: ["Root", "A", "B", "C", "D", "E", "F"], parents: ["", "Root", "Root", "A", "A", "B", "B"], values: [10, 20, 30, 15, 5, 10, 5], textinfo: "label+value", marker: { colors: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7], colorscale: "Viridis" } }, layout: { title: "Sample Plotly Treemap", height: 500, width: 800 } }; setupAccessibilityLayer() { const overlayEl = this.overlay.nativeElement; overlayEl.innerHTML = ''; const plotEl = document.querySelector('.plotly'); if (!plotEl) return; const plotData = Plotly.plot(plotEl).data[0]; const nodePositions = plotData._positions; this.graph.data.labels.forEach((label, index) => { const pos = nodePositions[index]; if (!pos) return; const nodeEl = document.createElement('div'); nodeEl.className = 'accessible-node'; nodeEl.style.left = `${pos.x0 * 100}%`; nodeEl.style.top = `${pos.y0 * 100}%`; nodeEl.style.width = `${(pos.x1 - pos.x0) * 100}%`; nodeEl.style.height = `${(pos.y1 - pos.y0) * 100}%`; nodeEl.setAttribute('aria-label', `${label},数值:${this.graph.data.values[index]}`); nodeEl.setAttribute('role', 'treeitem'); nodeEl.addEventListener('keydown', (e) => { switch(e.key) { case 'Enter': case ' ': Plotly.click(plotEl, {points: [{pointIndex: index}]}); e.preventDefault(); break; } }); overlayEl.appendChild(nodeEl); }); } }
方案二:增强图表本身的无障碍属性
直接为Plotly生成的SVG元素添加ARIA属性与键盘事件:
heatmapLoaded() { const svgEl = document.querySelector('.plotly .svg-container svg'); if (svgEl) { svgEl.setAttribute('role', 'img'); svgEl.setAttribute('aria-label', '树形图,包含Root、A、B等节点,展示各节点数值分布'); } const nodePaths = document.querySelectorAll('.plotly .treemap path'); nodePaths.forEach((path, index) => { path.setAttribute('aria-label', `${this.graph.data.labels[index]}:${this.graph.data.values[index]}`); path.setAttribute('tabindex', '0'); path.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { Plotly.click(path.closest('.plotly'), {points: [{pointIndex: index}]}); e.preventDefault(); } }); }); }
方案三:提供数据表格替代视图
为屏幕阅读器用户提供纯文本数据表格作为图表替代:
<div class="sr-only" aria-labelledby="table-title"> <h2 id="table-title">树形图数据表格</h2> <table> <thead> <tr> <th>节点名称</th> <th>父节点</th> <th>数值</th> </tr> </thead> <tbody> <tr *ngFor="let label of graph.data.labels; let i = index"> <td>{{ label }}</td> <td>{{ graph.data.parents[i] || '无' }}</td> <td>{{ graph.data.values[i] }}</td> </tr> </tbody> </table> </div>
添加屏幕阅读器专属样式:
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
内容的提问来源于stack exchange,提问作者PradeepPathak
相关产品推荐
相关产品推荐

