Adding Data-Driven Text to a Story Map

Hi there, I’m James, guest-posting on the Story Maps Developer’s blog. At Esri, I work with nonprofits and international organizations, and collaborate quite often with the Story Maps team. They asked me to share a recent customization I did to a Story Map.

Keeping the story current

One of the great advantages of a Story Map is the ability to convey information in a dynamic fashion. Because the map is live and reads data from services, it can display the most up to date information. Wouldn’t you like the data in your narrative to be equally dynamic, driven from the data? The WHO recently wanted this for their Story Map detailing the worldwide switch of Polio vaccine (UPDATE: sorry, this story map no longer available). In particular, they wanted to show the number of countries that had switched to the new polio vaccine using the latest information in their database, along with the date of report (the area in the red box below). The data was reported as summary text in a table that is part of the service being used in the Story Map:

With a bit of additional JavaScript and HTML code, this is pretty easy to implement. What you need to do with your Story Map is:

  1. Mark a place for the dynamic text in the narrative section.
  2. With JavaScript, query the service to get the statistic.
  3. Insert the statistic value into the dynamic text section.

Because we’re adding JavaScript to the application, we’ll need to download a copy of the Story Map (in this case, the Map Journal) and then host the result on our own website, which could be a web server or even an Amazon S3 bucket.

Letting it be part of the narrative

This step is pretty easy. When we enter text into a Map Journal, we normally do so through a rich text editor– this allows us to bold, underline or otherwise format the text without knowing any HTML. The editor interface also allows us to enter code view– the HTML representation for the text and formatting we’re typing. To set up the dynamic text, first enter your text as normal, with some place holder (like TEXT HERE) for the dynamic text. Then enter the code view and place a tag to enclose the placeholder (so it looks like <span>TEXT HERE</span>). Span tags signify an inline region where some form of custom formatting will be applied. Give the span tag a unique id attribute so we can later easily find it using JavaScript (so it looks like<span id=”REPLACE_ME”>TEXT HERE</span>). This image shows how this should look (instead of span, the id is placed in the em tag since that’s the one immediately around the text):

JavaScript– Getting the statistic & inserting it

The next part requires a little knowledge of both querying layers with the JavaScript API and DOM (HTML document) manipulation. I’ve posted an example based off of what WHO’s Story Map has on GitHub.

Dynamic Text Sample Code

To get the statistic, there are two methods, depending on how much data you’re expecting:

  1. For small datasets, you can query all features and do the processing in the browser. This is what the WHO Story Map does as it is reading a summary table with the text already formatted.
  2. Use the outStatistics parameter of the query to have the service summarize and then deliver the results. this would be preferred with a service with a lot of features or several different statistics.

Once the query is returned, I need to process the incoming data. Lines 22–24 of my sample just create an array of the feature attributes from the FeatureSet’s array of features, which makes the browser-side processing slightly easier. Since the data is already summarized, I can request the first value from the array of attributes (in WHO’s case, the array has only one attribute set). While not needed, I’m preparing to reuse this code by providing the ability to specify different statistics; SUM and AVERAGE are fairly easy to write.

The final step is to insert the new text into the document. In this case, I’m using Dojo’s built-in query module (different that the JSAPI’s Query module), which returns the list of objects that match the given CSS pattern (#REPLACE_ME = the part of the document with an ID (#) attribute of REPLACE_ME). The NodeList-html module loaded by the require statement gives the results a html() method to insert the text. This could be easily done with other libraries like jQuery or even just using the core JavaScript function document.getElementById().

Where to put the code in the Story Map

The Story Maps team have designed their applications to be extendable. At the bottom of the index.html file, there is a section marked for custom JavaScript. Since this needs to run once when the document is loaded, I placed it in the the application is ready section (inside the topic.subscribe(“tpl-ready”, function(){ … }); section). When the Story Map loads, the query will be made and then replace the initial text. You can see a copy of the index.html with the custom code also on Github, the custom code starts at line 344.

While the Story Maps are designed to meet most needs out of the box, with some basic HTML and JavaScript knowledge, it’s easy to customize them (or other apps) when you want something that’s one step beyond what’s currently in the box.