GithubHelp home page GithubHelp logo

mapbox / mapbox-gl-accessibility Goto Github PK

View Code? Open in Web Editor NEW
67.0 90.0 21.0 555 KB

An accessibility control for Mapbox GL JS

Home Page: https://labs.mapbox.com/mapbox-gl-accessibility

License: ISC License

JavaScript 100.00%
accessibility mapbox-gl-js voice-recognition

mapbox-gl-accessibility's Introduction

Mapbox GL Accessibility Plugin

Build Status

An accessibility control for mapbox-gl-js.

Note: This is a work in progress and we welcome contributions. See issues to learn what needs to be worked on!

Demo

  1. Go to https://labs.mapbox.com/mapbox-gl-accessibility
  2. Enable voice-over in your browser
  3. Press tab to hear the result

Usage

// Should be run after the map has been initialized

map.on('load', () => {
  map.addControl(new MapboxAccessibility({

    // A string value representing a property key in the data. This
    // will be used as the text in voiceover.
    accessibleLabelProperty: 'name',

    // The layers within the style that
    // 1. Contain the `accessibleLabelProperty` value as a key
    // 2. Should be used for voiceover.
    layers: [
      'poi-label',
      'transit-label'
    ]
  }));
});

MapboxAccessibility will locate features that belong to layers cooresponding to the layers option array and add button elements to the map. To hide these visually but still allow them to be picked up by a screen reader, add the following CSS to your page:

.mapboxgl-accessibility-marker {
  background: transparent;
  margin: 0;
  padding: 0;
  appearance: none;
  border-radius: 0;
  border: none;
  position: fixed;
}

.mapboxgl-accessibility-marker:focus {
  border: 2px solid black;
}

Developing

npm install & npm start

Visit http://localhost:5000/examples/ to load the demo. You also need to store an access token in localstorage. Open developer tools, locate the console tab and insert:

localStorage.setItem('accessToken', {your token});

Tests

MAPBOX_ACCESS_TOKEN={your token} npm run test

mapbox-gl-accessibility's People

Contributors

allthesignals avatar andrewharvey avatar dependabot[bot] avatar malwoodsantoro avatar tristen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mapbox-gl-accessibility's Issues

Label features by evaluated text-field

When accessibleLabelProperty isn’t set, queryFeatures() should set the aria-label attribute based on the evaluated value of the text-field property. Each feature in the feature querying results has a layer property that contains the evaluated values. This way, whatever a sighted user sees is exactly what a screenreader user would hear. Using the evaluated text-field value would even solve #6 as a side effect, since it would account for any changes already made by the gl-language plugin.

feature.marker.setAttribute('aria-label', feature.properties[this.options.accessibleLabelProperty]);

/cc @tristen @lukasmartinelli

Summarize visible places and roads

Some hidden element should summarize the state of the map. The iOS implementation in mapbox/mapbox-gl-native#9950 summarizes the following information whenever the user zooms in or out:

  • The zoom level
  • The number of visible annotations (markers)
  • The number of visible places (POIs), followed by a list of three visible places
  • The number of visible roads (#2)

https://github.com/mapbox/mapbox-gl-native/blob/dcd7da14f6627a09a5840a3046b5708449962f69/platform/ios/src/MGLMapView.mm#L2293-L2330

/cc @tristen

derive width and height from feature property

The accessible elements currently have a fixed width and height given in the plugin options. It would be nice to set from an expression evaluated per feature.

For example if you had a circle layer with variable circle-radius you could ensure the accessible element had the same width/height as the circle, so the focus style would match what's on the screen.

build a distributed bundle

similar to the other gl-js plugins, we could build a dist bundle which dev's can include in a script tag

I'm working on a PR for this, but getting stuck as it's giving me SyntaxErrors around:

clearMarkers = () => {

Not sure what ES level that syntax is...

Inherit mouse events

Map mouse events and their callbacks drive a large amount of 3rd party behavior in MapboxGL maps. I think the DOM nodes generated by mapbox-gl-accessibility should also inherit event callback behavior from the source features.

For example, if my map displays some zoning information, and I bind a click handler for each zone, the DOM nodes should also have click handlers bound to them...

Thoughts on this? A few drawbacks:

  1. Possibility of double-firing events
  2. Handlers might not stay in sync if un/binding occurs later

Make roads accessible

The iOS implementation in mapbox/mapbox-gl-native#9950 reads aloud the names of visible roads after naming all the visible POIs. In some settings, the nearby roads may provide better context to the user than the nearby POIs.

https://github.com/mapbox/mapbox-gl-native/blob/dcd7da14f6627a09a5840a3046b5708449962f69/platform/ios/src/MGLMapAccessibilityElement.mm#L138-L176

The following information is announced about each road:

  • Name
  • Route number
  • Whether the road is a one-way road
  • Whether the road is a divided road (in which case the geometry would be a multilinestring feature)
  • The general direction of the road (e.g., “north to south”)

Additionally, the road’s geometry is outlined. This is important to VoiceOver, which also allows the user to tap on any part of the map view to navigate to the accessibility element at the tap point. I’m not sure if it’s useful to outline the road geometry in GL JS.

/cc @tristen

Error when running `npm install & npm start`

This demo wasn't working a few minutes ago:
https://labs.mapbox.com/mapbox-gl-accessibility

Here's what I saw first:

then second after I added my token to local storage:

Now the map loads – I have not tested the reader:

Here’s my error log when I run npm install & npm start

0 info it worked if it ends with ok
1 verbose cli [ '/Users/domlet/.nvm/versions/node/v10.20.1/bin/node',
1 verbose cli   '/Users/domlet/.nvm/versions/node/v10.20.1/bin/npm',
1 verbose cli   'start' ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'prestart', 'start', 'poststart' ]
5 info lifecycle @mapbox/[email protected]~prestart: @mapbox/[email protected]
6 info lifecycle @mapbox/[email protected]~start: @mapbox/[email protected]
7 verbose lifecycle @mapbox/[email protected]~start: unsafe-perm in lifecycle true
8 verbose lifecycle @mapbox/[email protected]~start: PATH: /Users/domlet/.nvm/versions/node/v10.20.1/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/domlet/Documents/docs/mapbox-gl-accessibility/node_modules/.bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/usr/local/opt/ruby/bin:/Users/domlet/.nvm/versions/node/v10.20.1/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
9 verbose lifecycle @mapbox/[email protected]~start: CWD: /Users/domlet/Documents/docs/mapbox-gl-accessibility
10 silly lifecycle @mapbox/[email protected]~start: Args: [ '-c', 'run-p build start:server watch' ]
11 info lifecycle @mapbox/[email protected]~start: Failed to exec start script
12 verbose stack Error: @mapbox/[email protected] start: `run-p build start:server watch`
12 verbose stack spawn ENOENT
12 verbose stack     at ChildProcess.<anonymous> (/Users/domlet/.nvm/versions/node/v10.20.1/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:48:18)
12 verbose stack     at ChildProcess.emit (events.js:198:13)
12 verbose stack     at maybeClose (internal/child_process.js:982:16)
12 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
13 verbose pkgid @mapbox/[email protected]
14 verbose cwd /Users/domlet/Documents/docs/mapbox-gl-accessibility
15 verbose Darwin 19.6.0
16 verbose argv "/Users/domlet/.nvm/versions/node/v10.20.1/bin/node" "/Users/domlet/.nvm/versions/node/v10.20.1/bin/npm" "start"
17 verbose node v10.20.1
18 verbose npm  v6.14.5
19 error code ELIFECYCLE
20 error syscall spawn
21 error file sh
22 error errno ENOENT
23 error @mapbox/[email protected] start: `run-p build start:server watch`
23 error spawn ENOENT
24 error Failed at the @mapbox/[email protected] start script.
24 error This is probably not a problem with npm. There is likely additional logging output above.
25 verbose exit [ 1, true ]

Just submitting this in case anyone has time to take a look!

Accessibility Elements not created on map load

The accessibility elements are only created on moveend that means that upon loading a page none are created, but they should. They should also be refreshed when source data changes or something in the layer changes affecting if a feature is visible or not.

this.map.on('moveend', this.queryFeatures);
this.map.on('movestart', this.clearMarkers);

Provide more information about each POI

In the iOS implementation in mapbox/mapbox-gl-native#9950, each accessible place is labeled with its name but also given an “accessibility value” that provides the following facts:

  • The kind of place, using a cleaned-up type property that’s more or less extracted from OpenStreetMap tags
  • The kind of airport, rail station, or mountain based on its Maki image name
  • The peak’s elevation in the units preferred by the user’s locale

https://github.com/mapbox/mapbox-gl-native/blob/dcd7da14f6627a09a5840a3046b5708449962f69/platform/ios/src/MGLMapAccessibilityElement.mm#L87-L119

/cc @tristen

Order POIs by proximity to user location

When the geolocate control is enabled and trackUserLocation is enabled, the accessible elements could be ordered to start at the user location marker and radiate outward. At least this is how our iOS implementation does it. Otherwise, we could order the elements from top-left to bottom-right; either way, consistency helps the user know how far they’ve gotten through the list of elements.

/cc @tristen

Filter out duplicate features with the largest one

It looks like multiple accessible markers are being added when features span more than one tile

duplicate

From the docs on queryrenderedfeatures:

Because features come from tiled vector data or GeoJSON data that is converted to tiles internally, feature geometries may be split or duplicated across tile boundaries and, as a result, features may appear multiple times in query results.

Its extra work from the plugin but I wonder if it should filter out duplicates and then find the largest result so the width and height of the button is accurate. cc @andrewharvey

Automatically choose layers based on source layers

The iOS implementation in mapbox/mapbox-gl-native#9950 automatically chooses style layers to query based on the source layers they render. On iOS, we hard-code Mapbox Streets source v7 layers that correspond to information that would be labeled on a standard map:

https://github.com/mapbox/mapbox-gl-native/blob/dcd7da14f6627a09a5840a3046b5708449962f69/platform/darwin/src/MGLStyle.mm#L758-L774

I can see an argument for letting the developer choose which style layers to make accessible. That could be useful for data vis maps, which are less common on mobile platforms. Still, choosing a sensible set of style layers based on a sensible set of source layers would alleviate the developer from having to figure out all the layer IDs in their style, which can be a pretty tedious affair.

/cc @tristen

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.