Data visualization in the browser and getting started with ViiksetJS
When it comes to visualizing data in the browser, there is no shortage of options. Developer friendliness and performance are two important things to consider when adopting a data visualization tool. D3 is considered by many to be the gold standard in Javascript data visualization — and for good reason it is a powerful tool which can be used to create beautiful visualizations. One issue with using D3 in the context of React is the way that it manipulates the DOM. D3 manipulates the physical DOM, whereas React changes its own virtual DOM. Mixing these two methods of DOM manipulation is a good way to introduce hard to debug problems into your application. For more information this problem, see this talk.
Enter VX. This amazing library by Harrison Shoff brings the power of D3 to accessible React bindings. With it, you are able to only manipulate React’s virtual DOM while still having access to all of the great functionality of D3. It is performant and flexible. However, there is a learning curve associated with D3, and it can be difficult for new developers or those new to building visualizations. There are many libraries which try and abstract away this complexity, however, you are often forced to pay a performance penalty.
ViiksetJS hopes to bridge the gap between out of the box functionality and powerful flexibility. It has full inter-op between VX and allows not only for working with svg visualizations, but also canvas and the DOM itself. This allows for quick implementations or highly customized visualizations. ViiksetJS also works seamlessly with styled-components, allowing you to carry over your themes without any additional work. As we build some examples, you will see that flexibility and extensibility are core features of ViiksetJS.
First example
Let’s start with something simple. Say that we want to plot data containing the number of users and posts for a day over the course of several days:
[
{
“posts”: 4225,
“users”: 12220,
“time”: “2018–02–14T22:07:42.049+02”
},
{
“posts”: 3989,
“users”: 22455,
“time”: “2018–02–14T23:07:42.049+02”
},
{
“posts”: 3439,
“users”: 44512,
“time”: “2018–02–15T00:07:42.049+02”
},
{
“posts”: 3238,
“users”: 55112,
“time”: “2018–02–15T01:07:42.049+02”
},
{
“posts”: 3104,
“users”: 11111,
“time”: “2018–02–15T02:07:42.049+02”
},
{
“posts”: 3086,
“users”: 21135,
“time”: “2018–02–15T03:07:42.049+02”
},
…
]
First, we need to import the ChartArea
component.
This is the basis for many of the out-of-the-box visualizations
available in ViiksetJS. The ChartArea
component will
handle thing such as styling, scaling, tool-tips, etc. Second, we
will import the LineChart
which will be in charge of
rendering our visualization.
That’s it! Of course at this point, we want to customize that chart, so let’s do that:
<ChartArea
data={timeSeries.data}
numXTicks={isMobile ? 2 : 4}
color=”#2189C8"
stroke=”grey” >
// ...
What we did here is specify that on mobile, we only want to render 2 ticks on the x axis, set the color of the x and y axis ticks and toned the grid lines. An important thing to note here is that D3 will try and approximate the number of ticks you give as an argument, and does not always produce the exact number of ticks specified.
Second example
Let’s do another example where we will create a custom
glyphRenderer
and tool-tip. A
glyphRenderer
is placed on top all the layers of our
svg chart, which makes it useful for things such as annotations.
Create a new ChartArea
:
Perhaps we want to create a marker denoting a the start of a marketing campaign:
We can easily add this to the chart:
The following arguments are passed to the
glyphRenderer
function: width
,
height
, xScale
, yScale
, and
margin
. In our case, we only need to use the
xScale
function to correctly position our marker
horizontally. Since we want it to stay on the top of the chart, a
value of y={0}
is required.
Now let’s create the tool-tip. A quick note about custom
tool-tips: there are two different functions used for creating
custom tool-tips, tooltipRenderer
and
tooltipContent
. The
tooltipRenderer
function renders the container of the
tool-tip while the tooltipContent
function only
renders the content of tool-tip, which is the closest data point
to the current mouse position. In this case, we will only modify
the tool-tip content.
import format from 'date-fns/format'
import { ChartArea, LineChart } from 'viiksetjs'
const TooltipContent = ({ tooltipData }) => (
<div style={{ textAlign: "center" }}>
<p>{format(tooltipData.time, "MMM Do HH:mm")}</p>
<p>{tooltipData.messages} messages</p>
</div>
)
<ChartArea
data={data}
numXTicks={isMobile ? 2 : 4}
color=”#2189C8"
stroke=”grey”
glyphRenderer={({ xScale }) =>
<circle x={xScale(campaignStart.time)} y={0} r={6}/>
}
tooltipContent={TooltipContent}
>
<LineChart dataKey="messages" color="green" />
</ChartArea>
Third example
The third example is a demonstration on how to use the
DataContext
component. DataContext
takes
your data and returns the building blocks for visualization
including the calculated scale values, x and y points, as well as
the data itself. This is useful when working outside of the
pre-built charts or when working with thing such as canvas or
regular DOM elements.
Using the DataContext
component, we will create a
voronoi diagram
with HTML canvas. First, let’s seed some random data for our
diagram:
With this data, we can now create the
DataContext
component
Here, we have specified that the type of data we have is linear (
meaning that both x and y are numeric ) and that the
xKey
is named x
. The
DataContext
component will then calculate scales, x
and y points, and return that to us to use in our
Voronoi
component which we will now create.
With the help of the voronoi
function from VX and the
Path2D
browser API, we can create a diagram using the
data and dimensions passed to us from the
DataContext
component.
Conclusion
While this was just a small set of examples, there is much more than can be done with ViiksetJS, VX, and D3. I hope that this tutorial sparks your imagination and helps ease some of the cognitive and technical load of data visualization in the browser. Please feel free to contribute to the project!