How To Improve Image Accessibility for Esri Map Tour StoryMap Application

people holding a map of London, England

Providing the most accessible websites and browser-based applications should be a goal for every web developer.  Most of my work is with web mapping applications.  And while I consider myself relatively new to web accessibility, I am taking steps on improving this within my organization.

In this article, I wanted to share my solution for adding the alt attribute for img elements for the Esri Map Tour StoryMap application.  I have provided code samples at the end of the article.  In my experience working with Esri templates, it seems they often overlook the alt attribute for img elements.

According to the Mozilla Developer Network, the img element “embeds an image into the document.”  The alt attribute “holds a text description of the image, which isn’t mandatory but is incredibly useful for accessibility.”

screen shot of the esri map tour storymap web map application
An example of the Esri Map Tour StoryMap template

The Map Tour application blends a background webmap with a content block.  The content block contains the image, title, and descriptive text for each stop along a tour.  There is a carousel of all tour stops.  This carousel contains images.  And within the content block, there is an option to enlarge the image in a pop-out modal.  Users can move back and forth among the various stops along the tour.  By default, none of these image elements contain the alt attribute.

To remedy this issue, I decided to use a JavaScript-based solution.  I created a new JavaScript file (custom-script.js), and loaded into into the app’s index.html file using the loadJS function that is contained within a script element in the index.html file.  Esri provides some assistance with understanding how you can hook into the Map Tour template’s life cycle.   

I started by creating a function that could be called during the maptour-ready hook and maptour-point-change-after hook.  These hooks represent when the application is ready, and when a tour stop changes.  The function takes two parameters: 1) a string representing the title of the tour stop; and 2) the image element the alt text will be set on.  I set default text for the alt attribute.  If the title parameter is true, I combine that text with the default text.  If it is false, I use the default text to set the alt attribute.

During the maptour-ready hook, I loop over each of the images in the carousel and set the alt attribute.  I use the maptour-point-change-after hook to add the alt attribute for the image in the content block.

I did struggle with the image element in the pop-out modal.  Due to how the content was created and destroyed, my normal tricks would not work.  I learned about the MutationObserver.  This allow you to “watch for changes being made to the DOM tree[,]” which is exactly what I needed to do.

I’m sure my solution could use improvements in how I implemented the MutationObserver.  I constructed it in the maptour-ready hook.  Whenever the “button” is pressed on the image in the content block to expand the image into the modal, it fires the function to set the alt attribute.  It does this, but also fires a console error.  I have no idea why.

Overall, I am pleased with my solution.  I was able to add alt text to the images within the Map Tour StoryMap, and make the app more accessible to users.  But I am also frustrated that I had to work up this JavaScript-hack to implement something that should have been a standard feature of the template.  Hopefully Esri is working to accessibility a part of their future products.

ES6 Sample Code


require(["dojo/topic"], function(topic) {
// default alt text to apply to images
const defaultAltText = 'a view along the Yellow Breeches Creek';
// function to set alt attribute for images
function setAltText(title,img) {
// use grouped text if slide title text exists
if (title) {
// grouped text
const groupedAltText = `${defaultAltText}; map tour stop: ${title}`;
// set grouped alt text
img.setAttribute('alt', groupedAltText);
} else {
// set default alt text
img.setAttribute('alt', defaultAltText);
}
}
// The application is ready
topic.subscribe("maptour-ready", function(){
// colorbox element – container for modal image
const colorboxElement = document.getElementById('colorbox');
// options for mutation observer
const colorboxObserveOptions = {
childList: true,
subtree: true
};
// create mutation observer of colorbox div element
// console logs an error, but alt text is still set
const imgModalObserver = new MutationObserver(function() {
// title text
const titleText = document.getElementById('cboxTitle').innerHTML;
// img element
const imgElement = document.querySelectorAll('div#cboxLoadedContent > img.cboxPhoto')[0];
// set the alt text attribute
setAltText(titleText,imgElement);
});
// run observe method
imgModalObserver.observe(colorboxElement, colorboxObserveOptions);
// element containing thumbnail images
const thumbImgContainer = document.querySelectorAll('div.carousel-item-div > span');
// loop through span elements and add alt attribute to images
thumbImgContainer.forEach(function(element) {
// child img element – adding alt attribute to this
const imgElement = element.getElementsByTagName('img')[0];
// next sibling element – div with name of tour stop text
const siblingElementText = element.nextElementSibling.innerHTML;
// set the alt text attribute
setAltText(siblingElementText,imgElement);
});
}); // end maptour-ready
// After the new point is displayed
topic.subscribe("maptour-point-change-after", function(){
// featured image for map-tour
const featImg = document.querySelectorAll('div.member-image.current > img')[0];
// title text for image card
const titleText = document.querySelectorAll('div#placard > div.name')[0].innerHTML;
// set alt attribute text
setAltText(titleText, featImg);
}); // end maptour-point-change-after
});

Internet Explorer 11 Compatible Code


require(["dojo/topic"], function(topic) {
// default alt text to apply to images
const defaultAltText = 'a view along the Yellow Breeches Creek';
// function to set alt attribute for images
function setAltText(title,img) {
// use grouped text if slide title text exists
if (title) {
// grouped text
const groupedAltText = "".concat(defaultAltText, "; map tour stop: ").concat(title);
// set grouped alt text
img.setAttribute('alt', groupedAltText);
} else {
// set default alt text
img.setAttribute('alt', defaultAltText);
}
}
// The application is ready
topic.subscribe("maptour-ready", function(){
// colorbox element – container for modal image
const colorboxElement = document.getElementById('colorbox');
// options for mutation observer
const colorboxObserveOptions = {
childList: true,
subtree: true
};
// create mutation observer of colorbox div element
// console logs an error, but alt text is still set
const imgModalObserver = new MutationObserver(function() {
// title text
const titleText = document.getElementById('cboxTitle').innerHTML;
// img element
const imgElement = document.querySelectorAll('div#cboxLoadedContent > img.cboxPhoto')[0];
// set the alt text attribute
setAltText(titleText,imgElement);
});
// run observe method
imgModalObserver.observe(colorboxElement, colorboxObserveOptions);
// element containing thumbnail images
const thumbImgContainer = document.querySelectorAll('div.carousel-item-div > span');
// loop through span elements and add alt attribute to images
for (let i = 0; i < thumbImgContainer.length; i++) {
// child img element – adding alt attribute to this
const imgElement = thumbImgContainer[i].getElementsByTagName('img')[0];
// next sibling element – div with name of tour stop text
const siblingElementText = thumbImgContainer[i].nextElementSibling.innerHTML;
// set the alt text attribute
setAltText(siblingElementText,imgElement);
}
}); // end maptour-ready
// After the new point is displayed
topic.subscribe("maptour-point-change-after", function(){
// featured image for map-tour
const featImg = document.querySelectorAll('div.member-image.current > img')[0];
// title text for image card
const titleText = document.querySelectorAll('div#placard > div.name')[0].innerHTML;
// set alt attribute text
setAltText(titleText, featImg);
}); // end maptour-point-change-after
});

 

 

 

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s