Skip to content

First Navigable Chart

Let's put everything together!

The Final Result

Try it out:

  1. Click "Enter navigation area" (or tab and press Enter)
  2. Use and arrow keys to navigate
  3. Press Escape to exit

Trouble with Focus Indication

You may have noticed something important: the focus indicator is drawn by Bokeh, not by Data Navigator's rendered element. This is because Bokeh renders to <canvas> — pure pixels with no DOM elements to position over.

The Challenge with Canvas/Pixel Rendering

Most visualization libraries don't expose element coordinates. This means you can't position a DOM focus indicator precisely over a specific bar or point. The workaround is:

  1. Position the Data Navigator element to cover the entire chart
  2. Draw the focus indicator programmatically using the visualization library itself

This is why accessibility support from visualization libraries themselves is so important. Ideally, Bokeh (and others) would make charts navigable by default.

The Complete Code

js
import dataNavigator from 'data-navigator'

// Data for drawing focus outlines
const interactiveData = {
  data: [
    [[3, 2.75], [0, 0]],      // apple
    [[3.75, 4], [3, 2.75]]    // banana
  ],
  indices: {
    fruit: { apple: 0, banana: 1 },
    store: { a: 0, b: 1 }
  }
}

// 1. Define Structure - all elements cover full chart
const structure = {
  nodes: {
    _0: { 
      id: '_0', renderId: '_0', 
      data: { fruit: 'apple', store: 'a', cost: 3 },
      edges: ['_0-_1', 'any-exit'],
      semantics: { label: 'fruit: apple. store: a. cost: 3.' },
      spatialProperties: { x: 0, y: 0, width: 300, height: 300 }
    },
    // ... other nodes with same spatialProperties
  },
  edges: { /* ... */ },
  navigationRules: { /* ... */ }
}

// 2. Draw focus indicator by redrawing Bokeh chart
const drawFocusIndicator = (node) => {
  const fruitIndex = interactiveData.indices.fruit[node.data.fruit]
  const storeIndex = interactiveData.indices.store[node.data.store]
  const barData = interactiveData.data[fruitIndex]
  
  // Only outline the focused bar
  const line_color = storeIndex === 0 
    ? ['#000000', 'transparent'] 
    : ['transparent', '#000000']
  
  // Redraw chart with outline
  drawChart({ top: barData[0], bottom: barData[1], line_color })
}

// 3. On focus event, draw the indicator
element.addEventListener('focus', () => {
  drawFocusIndicator(nextNode)
})
css
/* Transparent overlay - doesn't block the chart visually */
.dn-manual-focus-node {
  background: transparent;
  border: none;
}

/* Browser focus ring still appears around the chart area */
.dn-manual-focus-node:focus {
  outline: 3px solid #1e3369;
  outline-offset: 2px;
}

Key Takeaways

spatialProperties for Focus Indication

Every node needs spatialProperties with x, y, width, height. For canvas-based charts where you can't position over specific elements, cover the entire chart and draw the indicator programmatically.

Render On Demand

We still only render one node at a time, keeping the DOM clean.

Next Steps

Congratulations! You've built your first accessible, navigable chart. Explore the Examples for more patterns, including SVG-based charts where element positioning is possible.

Released under the MIT License.