Creating a timeline of events based on customer feedback

Ryan Arnell
Feb 2, 2017 · 6 min read

Our customers requested a visual diagram that displays the overall ‘health’ of their whole environment over a time period. We discussed as a team and decided to create an interactive timeline. We designed an interactive timeline- representing all the events occurring in their environment over certain period of time.

I started exploring data visualization libraries including D3.js and viz.js along with some others and showed my team several examples to spark the ideas of what possible. I finally decided to use timeline of viz.js because it provided the planform we needed to develop. However, I knew I would have to customize the script significantly to meet our design and user experience needs.

We went through several iterations- based on customer feedback, I changed and modified the Viz.js script several times to fit the needs of the customers and the product.

Iteration 1

This is the first prototype I built. Using the viz.js library and some CSS tricks I was able to quickly mockup an interactive prototype that our researcher could test out with our clients.

Different types of events have their own event line

Positive client feedback: Really easy to understand since all the event types have their own line.

Design challenge to overcome: 4 lines took a lot of vertical space and we needed to be able to fit other elements. Also we needed to find a way to combine the events that occurred in a short time frame when zoomed out. In this demo, they overlap which obscures the relevant data for our users.

Iteration 2

In this second prototype we tried to solve the vertical space issue by combining all the events in one single line. We also introduced different circle sizes to put emphasis on repeated events and the severity of any particular issue. We also introduced the zoom controller at bottom to draw attention to this important feature.

Positive client feedback: Clients liked the idea of bigger bubble size. They seemed to have no problem understanding different event type through different color.

Design challenge to overcome: Overlapping events remained a problem in this version.We thought of creating a bigger bubble when events overlap. But in a client environment, in a worst case scenario , there could be hundreds of events. Keeping the bubble sizes relative over such vast data spread was a big challenge. One the other hand, relying on color only to display different event created new concern about accessibility.

Iteration 3

Issues solved: We solved the overlapping of events issue in this iteration. We discussed as a team and came up with the idea of “higher priority events take over”. So when two or more events combine, the combined event icon is derived from the most severe event. We also displayed combined events number above to clearly indicate how many events were combined.We redesigned the control buttons so that they are more compact to save space. We also introduced 4 different icon shape on top of color to overcome the accessibility issue. We moved the date and time information for the timeline below the events.

This was one of the most important feature requested by our customers. The library did not support this ‘grouping’ of events which they called clustering. Also we needed to do this while users zoom in or out.

Modifying the library: I assigned a specific class based on event type which appears without issues in non-cluster mode. I modified the `links.Timeline.ClusterGenerator.prototype.getClusters` method to add custom logic to identify which class it should add while in cluster mode.

The clustered event knows how many events it has. Then it loops through all the events to get the list of classNames (we use the className to identify what type of event it is).

This is how we prioritized event types, from most severe to least severe:
1. Error
2. Warning
3. Maintenance
4. Info/ok

Base on the priority, the cluster will show that specific style. I used following code to do so:

var classNames = [];
var clusterEventIds = [];
clusterItems.forEach(function (item) {
//custom code: picking highest one for cluster className
//className order by : [undefined, 'yellow', 'green-m', 'green']
var clusterClassName = undefined;
var selectedItemIndex = 0;
if (classNames.indexOf(undefined) > -1) {
clusterClassName = undefined;
selectedItemIndex = classNames.indexOf(undefined);
else if(classNames.indexOf('yellow') > -1) {
clusterClassName = 'yellow';
selectedItemIndex = classNames.indexOf('yellow');
else if(classNames.indexOf('green-m') > -1) {
clusterClassName = 'green-m';
electedItemIndex = classNames.indexOf('green-m');
else if(classNames.indexOf('green') > -1) {
clusterClassName = 'green';
selectedItemIndex = classNames.indexOf('green');

I set the className for the cluster object based on the above logic:

//custom code: assigning highest order className to the clustercluster.className = clusterClassName;//Set the className in `links.Timeline.ItemBox.prototype.updateDOM`:if (this.className) {
links.Timeline.addClassName(divBox, this.className);
links.Timeline.addClassName(divLine, this.className);
links.Timeline.addClassName(divDot, this.className);

Positive client feedback: Clients really liked this version. They could easily distinguish between events by the new icons. They could understand the grouping of events better because of the numbers displayed on the top of combined events.

Design challenge to overcome: We still were not happy with the controls. Also moving the date and time information below did not really work for the whole environment.

Iteration 4

In this iteration we came up with a better navigation. I attached the timeline with demo events so that they can be interacted together by hovering and clicking either section. I made the whole timeline accessible by keyboard. Also added Japanese language support.

One of the requirements of the project was the capability of highlighting the timeline object/cluster when user clicks on it. Also, it needed to notify external function to do additional tasks like scroll to specific event details connect in the page related to the clicked event. So, I needed to associate each event with the timeline object/cluster. First I added additional objects in the `links.Timeline.Item` function to include:

this.event_id = (data.event_id) ? data.event_id : null;
this.event_ids = (data.event_ids) ? data.event_ids: [];

While we were identifying the className of cluster of events, we also collected the event ids in `links.Timeline.ClusterGenerator.prototype.getClusters`:

var classNames = [];
var clusterEventIds = [];
clusterItems.forEach(function (item) {

Then I used className index to identify the priority event we are going to use when the mouse event fires and pass on the event_id and event_ids while creating Item:

var eventId = clusterItems[selectedItemIndex].event_id;// boxes onlycluster = this.timeline.createItem({
‘start’: new Date(avg),
‘content’: content,
‘group’: group,
‘event_id’: eventId,
‘event_ids’: clusterEventIds

Now I know which event is related to which timeline object. I needed to add mouse events to the Item and add proper callback functions with the eventId. So, I updated the `links.Timeline.ItemBox.prototype.updateDOM` function with following code:

links.Timeline.addEventListener(divDot, ‘mouseover’, function() {
if(mouseoverItemEventCallback != undefined) mouseoverItemEventCallback(this.event_id);
links.Timeline.addEventListener(divDot, ‘click’, function() {
if(clickItemEventCallback != undefined) clickItemEventCallback(this.event_id, divDot);
links.Timeline.addEventListener(divDot, ‘keypress’, function(event) {
var keycode = event.which || event.keyCode;
if(keycode == 13 && clickItemEventCallback != undefined) clickItemEventCallback(this.event_id, divDot);
itemToEventMapCallback(this.event_id, divDot, this.event_ids);

Other Modifications

Accessibility: I added following code so that timeline elements can be accessible via keyboard in `links.Timeline.ItemBox.prototype.updateDOM` function:

divDot.setAttribute(“tabindex”, 0);divDot.setAttribute(“role”, “button”);

Locale: viz.js comes with a locale feature. I had to use the predefined string constants along with the custom strings (‘AM’, ‘PM’, tooltip) and use those dynamically to make sure strings appears accordingly based on the browser locale.

Want to experience more? Check out this article in my personal blog to try the interactive timeline for yourself.

Special thanks to Alexander Wunschik from viz.js team for including my example in their showcase.

Iftekharul Islam is a Design and Front End Engineer at IBM based in Austin. The above article is personal and does not necessarily represent IBM’s positions, strategies or opinions.

Design at IBM

Stories from the practice of design at IBM

Ryan Arnell

Written by

Design & Front end Engineer @ IBM. I write about user friendly design and development || @ryanarnell

Design at IBM

Stories from the practice of design at IBM

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade