ScrollyTeller is a JavaScript library that streamlines the process of building scrolling data stories from tabular data
ScrollyTeller是一个JavaScript库,可简化从表格数据构建滚动数据故事的过程
In the last 5+ years, the data visualization community has seen a burgeoning of data storytelling in various forms. A popular format is the “scrollytelling” data story, where scrolling is the primary user interaction; scrolling controls both the pace of narrative text that moves across the screen, and animations within a dynamic data visualization or relevant content. Unlike video content, users can move forwards or backwards at their own pace and the data visualization can contain other interactions that reinforce the data story or allow further exploration of the data. From a web development perspective, the basic technical implementation of scrollytelling is relatively straightforward, and there are great examples of tutorials for how to create them that are described below. That said, there are many moving parts that must be managed: scrolling text, multiple interactive data visualizations, and the usual mobile responsiveness that is made more difficult by scrolling and “sticky” elements.
在过去的5年多的时间里,数据可视化社区看到了各种形式的数据故事讲述的兴起。 一种流行的格式是“拼写”数据故事,其中滚动是主要的用户交互。 滚动既可以控制在屏幕上移动的叙述文本的速度,也可以控制动态数据可视化或相关内容中的动画。 与视频内容不同,用户可以按自己的步调前进或后退,数据可视化可以包含其他互动,这些互动可以加强数据故事或进一步探索数据。 从Web开发的角度来看,滚动叙事的基本技术实现相对简单,下面将介绍如何创建它们的大量教程示例。 也就是说,必须管理许多移动部分:滚动文本,多个交互式数据可视化以及通过滚动和“粘滞”元素而变得更加困难的通常的移动响应能力。
measles outbreaks 麻疹暴发流行I work at the Institute for Health Metrics and Evaluation (IHME), where multiple stakeholders collaborate to create data stories about global health issues. In an organization context, managing the many components of a data story and the technical infrastructure around them is quite complex. Subject matter experts, data scientists, graphic designers, copywriters, and many other people play a role in the creation of a data story, but few are fluent in HTML or JavaScript. As data visualization developers it is our job to manage all of these elements while also creating complex interactive data visualizations. Because many data stories are time sensitive, streamlining all aspects of the creation process becomes very important, especially the technical aspects. Good storyboarding can make a huge difference in reducing unnecessary code changes and text edits, but modifications to all parts of a data story are common during the creation process.
我在健康指标与评估研究所( IHME )工作,那里有多个利益相关者协作创建有关全球健康问题的数据故事。 在组织环境中,管理数据故事的许多组件及其周围的技术基础架构非常复杂。 主题专家,数据科学家,图形设计师,文案作家和许多其他人在创建数据故事中发挥作用,但是很少有人会说流利HTML或JavaScript。 作为数据可视化开发人员,我们的工作是管理所有这些元素,同时创建复杂的交互式数据可视化。 由于许多数据故事都对时间敏感,因此简化创建过程的各个方面变得非常重要,尤其是技术方面。 好的情节提要可以在减少不必要的代码更改和文本编辑方面产生巨大的不同,但是在创建过程中,通常对数据故事的所有部分进行修改。
Bussed Out data story Bussed Out》数据故事Like many other software libraries, ScrollyTeller was created out of frustration. When creating scrollytelling data stories, I encountered several frustrations that centered around the management of editorial text and code.
像许多其他软件库一样, ScrollyTeller的创建也是出于无奈之举 。 在创建滚动讲述数据故事时,我遇到了一些围绕编辑文本和代码的管理而感到沮丧的问题。
First, I found that scrollytelling data stories can require a lot of very brittle, boilerplate code and HTML. Here’s an example of some HTML boilerplate you might need to create three text elements that scroll past your chart. There’s a lot of repetition here: each <div> element representing some narrative text (a “step” in scrolly parlance) differs only by the paragraph content and the index of the step, making this ripe for some templating.
首先,我发现讲故事的数据故事可能需要很多非常脆弱的样板代码和HTML。 这是一些HTML样板示例,您可能需要创建三个文本元素来滚动图表。 这里有很多重复:每个表示某些叙述性文本的<div>元素(滚动的措辞中的一个“步骤”)仅在段落内容和步骤的索引上有所不同,这使得它具有一些模板性。
<section id="scrolly"> <article> <div class="step" data-step="1"> <p>This is some narrative text that helps tell a story.</p> </div> <div class="step" data-step="2"> <p>Notice how much repetition there is in this code.</p> </div> <div class="step" data-step="3"> <p>And imagine having to change it often!</p> </div> </article> </section>Another example of brittle, boilerplate code in scrolling stories is the event handling code that links scroll events to actions in the data visualizations. Take Jim Vallandingham’s excellent how-to article describing how to build a scrolling data story. While the article is exceptional and very easy to understand, it’s easy to see how slight changes to the story can result in a lot of code change. I’ve modified Jim’s code slightly below, but the approach is still the same: defining an array of functions to respond to each scroll step.
滚动故事中易碎的样板代码的另一个示例是事件处理代码,该代码将滚动事件链接到数据可视化中的动作。 以Jim Vallandingham的出色的入门指南 文章为例, 该文章描述了如何构建滚动数据故事。 尽管这篇文章很出色并且很容易理解,但是很容易看到故事的微小变化会导致很多代码更改。 我在下面稍稍修改了Jim的代码,但方法仍然相同:定义一个函数数组以响应每个滚动步骤。
// define a function to handle each step's events const activateFunctions = []; activateFunctions[1] = showFillerTitle; activateFunctions[2] = showGrid; activateFunctions[3] = highlightGrid; // a plot module (the data visualization) function myPlot(functionArray) { function activate(index) { functionArray[index](); } return { activate }; } const plot = myPlot(activateFunctions); // react to events by index scroll.on('active', function(index){ plot.activate(index); });What if we wanted to switch the order of steps 2 and 3? In that case, we would need to change the HTML above to re-order the steps, then ensure that the new indices of steps 2 and 3 correspond to the functions we want to trigger. In longer data stories with much more complex edits, code changes like this become unwieldy and incredibly error prone. Furthermore, different developers might use different methods, such as hash mapping instead of array indices, to link “steps” with chart events, making collaboration between developers even more difficult.
如果我们想切换步骤2和3的顺序怎么办? 在那种情况下,我们将需要更改上面HTML以重新排列步骤,然后确保步骤2和3的新索引与我们要触发的功能相对应。 在具有复杂得多的编辑的较长数据故事中,像这样的代码更改变得笨拙且极易出错。 此外,不同的开发人员可能会使用不同的方法(例如哈希映射而不是数组索引)将“步骤”与图表事件链接在一起,从而使开发人员之间的协作更加困难。
Another frustration is that, as a data visualization developer in a large organization, I find myself responsible for making many text changes to the narrative part of the story. Those text changes may come from copywriters, researchers, designers, or my own minor changes to update text styles. While the collaborative aspects of the editorial process are incredibly rewarding, modifying editorial text in code is tedious and places me (the web developer) between the editor and the copy they are working on. That “editorial friction” can slow the process down and stifle the collaborative creative process that makes visual stories possible.
另一个令人沮丧的是,作为大型组织中的数据可视化开发人员,我发现自己负责对故事的叙述部分进行许多文本更改。 这些文本更改可能来自撰稿人,研究人员,设计师,或者我自己进行的较小更改来更新文本样式。 尽管编辑过程的协作方面非常有意义,但是修改代码中的编辑文本却很繁琐,这使我(Web开发人员)介于编辑器和他们正在处理的副本之间。 这种“编辑摩擦”会减慢流程,并扼杀使视觉故事成为可能的协作创作过程。
Thaaaanks Peter Thaaaanks彼得So how does ScrollyTeller help fix these issues? Let’s talk about a few key features that alleviate these problems, and a few more that help multiple developers work together on a story. The use cases below are just brief overviews that highlight key features of the library. For a much more in-depth look, see the ScrollyTeller tutorial, which serves as both a template for creating scrolling data stories a tutorial for web developers on how to use the library.
那么ScrollyTeller如何帮助解决这些问题? 让我们谈谈缓解这些问题的一些关键功能,以及一些有助于多个开发人员共同处理一个故事的功能。 下面的用例只是简要概述,突出显示了库的关键功能。 要获得更深入的了解,请参见ScrollyTeller教程 ,该教程既是创建滚动数据故事的模板,又是Web开发人员如何使用该库的教程。
The scrolling data story that serves as a tutorial for how to use ScrollyTeller to create a scollytelling data story. 滚动数据故事,用作如何使用ScrollyTeller创建编排数据故事 的教程 。ScrollyTeller’s first functionality was to use JavaScript to template HTML text boxes that scroll in a data story using data from .csv files, Google/Excel spreadsheets, or database tables. Each row in the data table represents one scrolling text box, with various text fields to populate a title, paragraph, and some link text. This relatively simple functionality reduces the boilerplate HTML that data visualization developers need to manage and puts editorial power back in the hands of copywriters because almost anyone can edit a data table.
ScrollyTeller的第一个功能是使用JavaScript模板化HTML文本框,这些文本框使用.csv文件,Google / Excel电子表格或数据库表中的数据在数据故事中滚动。 数据表中的每一行代表一个滚动文本框,其中包含用于填充标题,段落和一些链接文本的各种文本字段。 这种相对简单的功能减少了数据可视化开发人员需要管理的样板HTML,并将编辑权交还给撰稿人,因为几乎任何人都可以编辑数据表。
ScrollyTeller tutorial showing which columns in a data table correspond with each HTML element in a scrolling text box ScrollyTeller教程中的动画,显示数据表中的哪些列与滚动文本框中的每个HTML元素相对应When creating the Tobacco Control and Child Mortality visualizations, we configured a development version of our data story to fetch data from a shared Google Spreadsheet using the Google Spreadsheets API. The data visualization team set up the basic structure of the spreadsheets from storyboards that outlined the basic story flow, then we shared the spreadsheets with our editorial teams. Copywriters and other stakeholders could then update the text in the Google Spreadsheet and reload the visualization to see the changes in real time, significantly reducing the burden of making minor text edits in code. Giving editorial teams control over the text also allowed them to feel much more in control of the story, and propose new changes to the story by adding new rows to the spreadsheet. The data visualization team could then add the relevant events and chart animations to complete the story.
在创建烟草控制和儿童死亡率可视化时,我们配置了数据故事的开发版本,以使用Google Spreadsheets API从共享的Google Spreadsheet获取数据。 数据可视化团队从概述了基本故事流程的情节提要板上建立了电子表格的基本结构,然后我们与编辑团队共享了电子表格。 然后,撰稿人和其他利益相关者可以更新Google Spreadsheet中的文本并重新加载可视化文件以实时查看更改,从而大大减少了在代码中进行少量文本编辑的负担。 让编辑团队对文本进行控制还可以使他们对故事有更多的控制权,并通过向电子表格添加新行来对故事提出新的更改。 然后,数据可视化团队可以添加相关事件和图表动画以完成故事。
A Google Spreadsheet containing the tabular data for a scrolling data story. 包含滚动数据故事的表格数据的Google Spreadsheet。At IHME, many of our web tools are used by policymakers around the world, so translating text and localizing our applications is an important, if not very time consuming task. While creating the the Tobacco Control visualization, we found that translation of the application into several languages was much easier with the text components of the visualization already in tabular form. In that case, we were able to share our spreadsheets containing the story “narration” as-is with translators, who returned the spreadsheets, translated, in our data format (we also hid the columns that didn’t need to be translated using the “hide columns” functionality in Google Spreadsheets). Upon receiving the translated text, we only needed to add a language column to our data tables, fetch data by language, and our visualization was translated without any major code changes (other than adding the dropdown to change language).
在IHME ,全球许多决策者都在使用我们的许多Web工具,因此翻译文本和本地化应用程序是一项重要的任务,即使不是很耗时的任务。 在创建“ 烟草控制”可视化时,我们发现使用表格形式的可视化文本组件,将应用程序翻译成多种语言要容易得多。 在这种情况下,我们可以与翻译人员按原样共享包含故事“旁白”的电子表格,翻译人员以我们的数据格式返回已翻译的电子表格(我们还隐藏了不需要使用Google电子表格中的“隐藏列”功能)。 收到翻译后的文本后,我们只需要在数据表中添加语言列,按语言获取数据,就可以对可视化进行翻译,而无需进行任何重大代码更改(除了添加下拉菜单以更改语言)。
The Tobacco Control visualization: available in English and Spanish 烟草控制可视化:提供英语和西班牙语Creating the interactive data visualizations (charts) that underpin many data stories is complicated enough, so it’s nice to have a framework in place to handle the scroll events that trigger animations in the visualizations. There are many libraries that handle scroll events, and ScrollyTeller relies heavily on the much lighter weight Scrollama library, written by Russell Goldenberg, to detect scroll events and scroll progress.
创建支持许多数据故事的交互式数据可视化(图表)非常复杂,因此最好有一个框架来处理触发可视化中的动画的滚动事件。 有许多处理滚动事件的库,而ScrollyTeller很大程度上依赖于重量更轻的Scrollama库 (由Russell Goldenberg编写)来检测滚动事件和滚动进度。
Each scrolling text box corresponds to a chart view 每个滚动文本框对应一个图表视图Like Scrollama, ScrollyTeller has several event handling functions that are triggered when a block of text scrolls to a predefined percentage of the page height. ScrollyTeller also provides framework for triggering chart events: each narrative text block contains a trigger field that can contain a JSON string. The JSON string is parsed to a JavaScript object literal and passed to an event handler to trigger changes to the chart. Below is an example of two rows representing narrative text with their trigger field shown. In this case, there is just a year property that changes from 1950 to 2008 between the two rows.
与Scrollama一样,ScrollyTeller具有多个事件处理功能,当文本块滚动到页面高度的预定义百分比时会触发这些事件处理功能。 ScrollyTeller还提供了触发图表事件的框架:每个叙述性文本块均包含一个可以包含JSON字符串的触发字段。 JSON字符串被解析为JavaScript对象文字,并传递给事件处理程序以触发对图表的更改。 以下是两行代表叙事文本的行的示例,并显示了其触发字段。 在这种情况下,两行之间只有一年的属性从1950年更改为2008年。
Tabular data showing the title and trigger JSON for the data story below 表格数据显示标题和以下数据故事的触发JSONWe can configure a chart component to update when new state is passed to it, in this case, in the form of the year property that transitions from the 1950 data to the 2008 data.
我们可以配置一个图表组件,以便在将新状态传递给它时进行更新,在这种情况下,形式为year属性,它从1950年的数据过渡到2008年的数据。
year property is passed to it from the JSON trigger. year属性传递给它时,气泡图组件将在年份之间转换。A code snippet is shown below that summarizes how the event handling functionality works in ScrollyTeller. Here we are using es6 destructuring to pick properties from an object passed to onActivateNarrationFunction(). In this case, we pick the year property from the state variable, and pass that to our graph’s render function. The ScrollyTeller configuration also provides a function (buildGraphFunction()) to build a data visualization component (a graph) and stores a reference to the component as a graph property for use in the event handler. Notice that the state variable could contain any JSON parse-able entity: arrays, strings, numbers, or even nested objects.
下面显示了一个代码段,总结了事件处理功能在ScrollyTeller中的工作方式。 在这里,我们使用es6解构从传递给onActivateNarrationFunction()的对象中选择属性。 在这种情况下,我们从状态变量中选择year属性,并将其传递给图形的render函数。 ScrollyTeller配置还提供了一个函数( buildGraphFunction() )以构建数据可视化组件(图形),并将对该组件的引用存储为图形属性,以供事件处理程序中使用。 请注意,状态变量可以包含任何JSON可解析的实体:数组,字符串,数字甚至是嵌套对象。
const scrollyTellerConfiguration = { // Section Configuration object // event handler triggered when text box reaches 50% of page height onActivateNarrationFunction: function ({ // section configuration containing a reference to a graph component sectionConfig: { graph }, // state = JSON.parse(trigger) state: { year }, }) { if (graph && year) { graph.render({ year }); } }, };In practice, we find that passing JSON to chart functions makes the process of modifying and updating charts highly flexible, so responding to requests to change the story don’t usually require code changes at all. Story changes might just mean modifying or adding a property to JSON in a Google Spreadsheet. This means that during collaborative meetings, we can sometimes make changes in real time without having to redeploy code to see the results.
在实践中,我们发现将JSON传递到图表函数使修改和更新图表的过程变得非常灵活,因此响应更改故事的请求通常根本不需要更改代码。 故事更改可能只是意味着在Google Spreadsheet中修改属性或向JSON添加属性。 这意味着在协作会议期间,我们有时可以实时进行更改,而无需重新部署代码以查看结果。
It’s worth noting here that like many scroll based libraries, ScrollyTeller provides a progress property to an onScroll() function for smoothly transitioning between chart states as text scrolls up and down the page. We find that animations that link directly to scroll progress are much more satisfying and allow much finer control over chart interactions.
在这里值得注意的是,像许多基于滚动的库一样,ScrollyTeller为onScroll()函数提供了一个progress属性,以便在文本在页面上上下滚动时在图表状态之间平稳过渡。 我们发现直接链接到滚动进度的动画更加令人满意,并且可以更好地控制图表交互。
With increasingly complicated components come increasingly complicated JSON triggers. Sometimes we might need three or four properties to control chart styles, series visibility, highlighted data points, or pre-specified ranges of data. To maintain consistent state when scrolling forwards or backwards, we would have to store all of the state as JSON in the trigger field of every data row. This turns out to be very verbose and difficult to maintain, so we added functionality to accumulate trigger properties from the top down to ScrollyTeller.
随着组件越来越复杂,JSON触发器也越来越复杂。 有时我们可能需要三个或四个属性来控制图表样式,系列可见性,突出显示的数据点或预先指定的数据范围。 为了在向前或向后滚动时保持一致的状态,我们必须将所有状态作为JSON存储在每个数据行的触发字段中。 事实证明,这非常冗长且难以维护,因此我们添加了从上到下累积到ScrollyTeller的触发器属性的功能。
In the table above, the series of JSON triggers is shown in the center column, with the merged state property that ScrollyTeller passes to the event handlers. Notice that the state at each row consists of the accumulated triggers that preceded it, so advancing backwards removes or updates the previous state variable accordingly.
在上表中,一系列JSON触发器显示在中间一列,其中包含ScrollyTeller传递给事件处理程序的合并状态属性。 请注意,每行的状态都包含在其前面的累积触发器,因此向后前进会相应地删除或更新前一个状态变量。
ScrollyTeller configuration is grouped by sections, so each section can have its own data, chart components, and state. We found this feature to be very useful when multiple developers collaborate quickly on the same project. Adding a new chart usually just means importing the relevant configuration and adding it to a JavaScript object that ScrollyTeller receives upon instantiation.
ScrollyTeller配置按部分分组,因此每个部分都可以具有自己的数据,图表组件和状态。 我们发现当多个开发人员在同一个项目上快速协作时,此功能非常有用。 添加新图表通常仅意味着导入相关配置并将其添加到ScrollyTeller实例化时接收JavaScript对象。
ScrollyTeller configuration also standardizes the control flow associated with data stories, providing asynchronous functions to fetch narrative text tables and chart data, modify the chart data, then build the chart when the application loads. The data and graph in each section are stored as properties and are accessible as arguments in all of the event handlers.
ScrollyTeller配置还标准化了与数据故事相关的控制流,提供了异步功能来获取叙述性文本表和统计图数据,修改统计图数据,然后在应用程序加载时构建统计图。 每个部分中的数据和图形都存储为属性,并且可以在所有事件处理程序中作为参数进行访问。
ScrollyTeller also provides configurable tracking of scroll events in Google Analytics at the section level, or even down to the level of each narrative text block. We found this feature useful for determining how far users progressed in a data story, where we “lost” them, and where users spent the most time.
ScrollyTeller还提供了可配置的Google Analytics(分析)滚动条在部分级别甚至每个叙述性文本块级别的跟踪事件。 我们发现此功能对于确定用户在数据故事中进行的进度,“丢失”的位置以及用户花费最多时间的位置很有用。
I hope this provides a high level view of ScrollyTeller and how it can be used to make creating scrolling data stories much smoother, more collaborative, and more flexible. To get started, I highly recommend checking out the ScrollyTeller repo, which can serve as a template project for your own data story, and going through the ScrollyTeller tutorial in detail to understand how to set up a project.
我希望这可以提供ScrollyTeller的高级视图,以及如何使用它来使滚动数据故事的创建更加流畅,更加协作且更加灵活。 首先,我强烈建议您查看ScrollyTeller仓库 ,该仓库可以用作您自己的数据故事的模板项目,并详细阅读ScrollyTeller教程以了解如何设置项目。
I would like to acknowledge IHME for supporting this project and the developers on IHME’s Data Visualization team who contributed to ScrollyTeller and the data stories described in this article, including Evan Laurie, Katherine Beame, David Schneider, Komal Ali, Michael Fernandes, and Ben Hurst. Please don’t hesitate to get in touch if you want to contribute to this project or are interested in working with our team. I would also like to acknowledge the many other developers upon whose open source software ScrollyTeller is based, especially Russell Goldenberg’s Scrollama library that provides the scroll event handling functionality that underpins ScrollyTeller.
我要感谢IHME支持该项目以及IHME数据可视化团队的开发人员,他们为ScrollyTeller和本文所述的数据故事做出了贡献,包括Evan Laurie , Katherine Beame , David Schneider , Komal Ali , Michael Fernandes和Ben Hurst 。 如果您想为这个项目做出贡献或有兴趣与我们的团队合作,请随时与我们联系。 我还要感谢开源软件ScrollyTeller所基于的许多其他开发人员,特别是Russell Goldenberg的Scrollama库,该库提供了支持ScrollyTeller的滚动事件处理功能。
Best of luck telling great data stories!
祝您好运,讲大数据故事!
翻译自: https://medium.com/ihme-tech/creating-data-stories-with-scrollyteller-601a34327545
相关资源:python 京东预约抢购茅台脚本插件 一键运行