Interactive infographics with plain Javascript
Today’s browsers let us connect information in ways never seen before. Infographics is one such area. As a pictogram, it is an excellent visualisation tool. As an interactive webpage, you can achieve a new level of engagement with just a little bit of coding.
Many open-source libraries render fantastic infographics. Our favourites are D3, and vis.js. However, there are other times when we needed features that aren’t available from public libraries.
Let’s build an interactive infographic with plain Javascript.
The Google Cloud Platform (GCP) is like a candy store to a web developer. Its product categories are more than fingers can count and each interconnects in different ways to solve complex problems.
The GCP “Org chart”. Official source: Google Cloud Platform
If we harness the power of a modern browser to showcase the benefits of GCP products, how would the UI look like? Is it possible to use basic Javascript techniques to produce extraordinary results?
Our design approach is based on the idea of using a consistent and persistent User Interface (UI) to tell an engaging story. Let’s rethink design in two areas:
UI concept: the looking-glass
Let’s introduce the notion of nodes and links as the basic building blocks of our design workflow.
Nodes are the start and end points. For example, a bus stop can be called a node. A bus route from one node to another can be called a link. A group of related nodes and links can be called a branch
.
Basic building blocks : each node describes a set of unique relationships
Node elements. We can use an HTML element and a unique id to describe a node. For example, node11
would be node #1 of branch #1. Similarly, node12
would be node #2 of branch #1. In the above diagram, that would be circle “1” and “2”. The bus route #1 (i.e. branch #1) would connect circle “1” and “2”, as well as other circles (i.e. 2a,3,3a,3b).
Let’s use the style
attribute to describe the unique position, shape and behaviour of each element. You can use any HTML, CSS, icons or images to represent a node or link. The circular nodes in our videos are simply div tags with a CSS border-radius
.
<div id=”node11" style=”…”>1–1 Occupation Name</div><div id=”node12" style=”…”>1–2 Occupation Name</div>
Link elements. Links connects nodes. For example, link1112
connects node11
and node12
.
<div style=”...” id=”link1112"></div>
Tip: Use an image overlay to guide your CSS positioning of the HTML elements.
The nodes and links we’ve discussed are essentially DOM elements at browser runtime. The DOM, or Document Object Model, is a tree-like data structure for representing HTML elements and mapping content onto a physical display.
Conversely, we can also interact with any display elements by manipulating the DOM. In our project, we would like these nodes and links to respond to a specific user action such as a mouseover
event.
document.addEventListener( "mouseover", myCustomFunction );
mouseover
detects a mouse cursor hovering over a particular DOM document such as a button.myCustomFunction
to do something (e.g. spring an animation sequence or retrieve information from a database).We’ll use this Javascript API to detect user actions and trigger a whole range of functionalities to create interactive web pages.
Let’s bind the node and link elements to its event listeners
within a loop
in two steps:
Step one. Assign the model (data).
Store your HTML element’s unique id
values as an item[]
array.
var item = [‘11’,’12',’1112',‘21’,’22',’2122',...];
Each value in the item[] array will correspond to the unique id value of each node or link (e.g. 11
refers to node11
; 1112
refers to link1112
.). You can think of item[] as a master registry.
Next set up legend[]
to hold an array of objects
. Each object is a dataset that will correspond to a specific user action.
var legend = {'item11' : { "node" : ['11'], "links" : [] },'item12' : { "node" : ['11','12'], "links" : ['1112'], },...}
node11
, the object item11
will call node11
for CSS targeting.item12
calls node11
, node12
, and link1112
for CSS targeting.item
is just a prefix label. Use your naming convention.Let’s take a moment to consider the implication of the above schema. Not only have we created a system to store content, we have also created a graph relationship to describe data connections.
We’ve reduced tons of code; sped up the design workflow; and separated the view from the model (data). Let’s move on to build the view engine.
Tip: For dynamic content management, consider encoding your dataset as JSON and access them via a database. Also, use any tools to edit your dataset and HTML layouts.
Step two. Loop through each HTML element to associate event listeners programmatically.
while (item[i]) {itemElement[i] = "node".concat(item[i]);itemElementName[i] = document.getElementById( itemElement[i] );itemElementName[i].addEventListener( "mouseover", mouseOver );itemElementName[i].addEventListener( "mouseout", mouseOut );...i++;}
while
iterates through the id values of each DOM element registered at item[]
.“item”.concat(item[i])
reattaches any custom prefixes you may have (i.e. “node”) to match the actual id values.itemElementName[i] = document.getElementById( item[i] )
builds an array of DOM references.mouseover
” and “mouseout
” binds each DOM element to a user action.Tip # 1: Mobile and touch devices have its own set of event listeners such as _touchstart_
and _touchmove_
. Use them to create responsive designs.
Tip #2: Use the “passive” parameter on your touch or wheel event listeners to improve browser performance like so:
document.addEventListener('touchstart', onTouchStart, {passive: true});
Customising interactive behaviours with CSS
We can create custom functions mouseOver
and mouseOut
to apply CSS effects:
function mouseOver(event) {for (var i in legend[this.id]["node"]) {var currKey = "node".concat(legend[this.id]["node"][i]);document.getElementById(currKey).style.background = "grey";...}for (var i in legend[this.id]["link"]) {var currKey = "link".concat(legend[this.id]["link"][i]);document.getElementById(currKey).style.border = "1px solid#000";...}
}
mouseover
to bind a DOM element to your custom function mouseOver
. This function takes in the event
parameter (provided by the browser) to give the active this.id
value.legend[this.id][“node”]
identifies the dataset for applying CSS targeting._for_
loops through the collection legend[]
.In our example, the mouseOver
function turns the background colour of the targeted node(s) grey.
Use the same idea on link
elements. In our example, we changed the colour of links1112
from grey to solid black when a mouse pointer hovers over node12
(node11 and node12 also turn grey).
Next, “reset” the CSS behaviour as soon as the cursor exits the current DOM element (see bold).
function mouseOut() {for (var i in legend[this.id]["node"]) {var currKey = "node".concat(legend[this.id]["node"][i]);document.getElementById(currKey).style.background = "unset";...}
for (var i in legend[this.id]["link"]) {...}
}
Our GCP infographics use SVG extensively to support high-def resolution for a zooming feature that’ll be implemented in the next part of our discussion.
To change the HTML/CSS circle 1
, or node11
, into a hexagonal SVG shape, simply wrap your SVG content within an HTML container (see bold).
<div id=”node11" style=”display:flex; align-items:center;"><svg><path d="...some paths"/></svg><div style="align-items:center; width:100%;">My Text Label</div></div>
id=”node11"
references the same node. Instead of rendering an HTML circle shape, it now contains SVG data.display:flex
and align-items:center
uses Flexbox, now supported on all major browsers, to automatically align our SVG and text content.<svg>...</svg>
contains the SVG data that describes our zoomable icon. Visit the official GCP icon library to download the complete icon pack.We added SVG to the model. Let’s see how a sample layout with GCP content looks so far.
Graph relationships and interacting with SVG content
scale3d
effect to create impactful highlighting effects.dashed
to illustrate different relationships.We’ve devised a schema and a view engine as a foundation for our design workflow.
In the next part, we’ll add navigation capabilities to the UI.
This story is a 5-part series on creating interactive infographics with Javascript. We’ve handpicked what’s important so that you can get to the essential parts quickly and adapt them in your project. It does help that you have some knowledge of CSS and HTML. Non-relevant code blocks are glossed over.
All video illustrations are screen captured from a Chrome browser. While the demo is based on GCP, you can find applications in org charts, ecosystems, subway maps, flowcharts, progression trees, network topologies, and any graph diagrams.
Many thanks to Chuck Erickson and the Google Team for the wonderful GCP solutions icon and diagram pack.
Part-one → You’re are here.
Part-two adds navigation features to browse content.
Part-three adds a dynamic mini-map to enhance navigation.
Part-four adds an inline UI to access layered content.
Part-five demonstrates why it is so easy to create UIs with a human touch.
If you enjoyed this story, you can find more at Pageii Studio.