📊 billboard.js 2.0 is out! 🎉🎊, more smaller and faster.

Jae Sung Park
6 min readJul 17, 2020

--

After the several months of work, proud to announce a long waited major update came out today!

For the detailed info, please checkout the v2 changelog:
https://github.com/naver/billboard.js/wiki/CHANGELOG-v2

# install the v2
npm install billboard.js

TL;DR

  • Moved the code base to TypeScript
  • Restructured whole file system & class architecture
  • Smaller build size & run faster
  • Maintained backward compatibility.

Major internal changes

We decided to move whole codebase to TypeScript to make more easier for contributors to access and understand codes.

And also re-architecture were applied from the ground to facilitate the maintenance of the library.

https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#updates-on-private-state-variables

Yay! smaller build size & performance improvements

1) Bundle size

Reducing delivery size is a strong key to improve loading efficiency. In most cases, not every chart types are used in all circumstances. Those non used types codes were delivered regardless of the usage in previous version.

v1 was providing UMD style module exports, and it was difficult for users’ bundlers to tree-shake non-used codes at all.

To improve on this, starting from v2, will provide ESM build. And from now chart types and interaction modules are named exported.

Interaction functionalities are great, but they’re not always used. For the majority of cases with the purpose of visualizing data, interactions such as: data selection, subchart and zoom functionality aren’t required.

This means including all those related codes in your bundle are useless. Just include when they’re used.

import bb, {
area,
areaLineRange,
areaSpline,
areaSplineRange,
areaStep,
bar,
bubble,
donut,
gauge,
line,
pie,
radar,
scatter,
spline,
step,

// interaction modules
selection, subchart, zoom
}
bb.generate({
...,
data: {
// by calling `line()`, will make internally extend 'line' type related functionality.
// line() will return "line" string.
type: line(),

// or specifying type for each data
types: {
data1: bar(),
data1: spline()
},

selection: {
enabled: selection() // selection() will return 'true'
}
},

subchart: {
show: subchart() // subchart() will return 'true'
},

zoom: {
enabled: zoom() // zoom() will return 'true'
}

Import what are used only. If they aren’t used, will be excluded from the bundle.

So, how many bytes can be saved?

This approach will reduce your bundle size approximately 20% ~ 43%, based on your options.

https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#example-of-size-reduction-by-types

2) Node size reduction

Keeping big node size will impact runtime performance. v1 where adding lots of different<g> nodes wrappers to handle types transforms via .transform() API.

But in most of normal use case, transformation aren’t really practical. v2 deprecated .transform() API to remove the possibility to transform chart types from one to another.

This derived to not generate and append redundant nodes, generating necessary nodes only by its types used.

As a result, the size decreased from 5 ~ 50%!

https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#reduced-node-generation

3) Benchmark

Based on the bundle size and node size reduction, the runtime performance has been improved. Note that not in every occasion of the usage, but in a average the performance has been improved in a range of ~50%.

Try the benchmark comparison by your own.
https://output.jsbin.com/pecafih

What are the new options?

point.focus.only

This new option, will make to display a data point when is hovered(focused).

Demo: https://naver.github.io/billboard.js/demo/#Point.FocusOnly

Using this new option has great advantage in performance. To archive this same behavior in v1, the following option was used.

point: {
r: 0,
focus: {
expand: {
r: 5
}
}
}

For the simplicity, this works fine. Internally generated each data points <circle> nodes and controlled by its visibility. This means, for massive data displays, <circle> nodes size will increase relative the data sizes.

Well, when node increases, it eventually bring the degradation of performance.

This new option, will generate only one <circle> node per data to prevent performance impact. You can use this option simply by:

point: {
focus: {
only: true
}
}

label.threshold for bar/gauge

Visualizing data values text is very clear approach for user to understand, but for those circumstances where the portion are small and texts are overlapped each other, will make harder to understand.

In this case, hiding text rather than showing is the best alternative.

Data label threshold was supported only for pie type, and as an extension of this, we added new label.threshold options for bar and gauge types.

bar | gauge: {
label: {
threshold: 0.1
}
}
Data label texts are shown base on the threshold

log scale for x/y Axes

Another new way to scale your data is added. From this v2 release, added log scale support!

Demo: https://naver.github.io/billboard.js/demo/#Axis.LogScales

To use log scale axis, is very simple. But with some limitations to follow.

  • The data values must be exclusively-positive.
  • Minimum value for log scale axis should be > 0, where log 0 is undefined.
axis: {
x | y: {
type: "log"
}
}

How to migrate from v1?

If you’re already using v1, is quite easy to migrate to v2.

Migration Guide to v2: https://github.com/naver/billboard.js/wiki/Migration-Guide-to-v2

Updates on callback options context

From v2, all callback-ish options(like tooltip.onshow, data.onclick, etc.) context function will be the current chart instance by default.

If you have been using context parameter, have to replace it.

tooltip: {
position: function() {
this; // <-- current chart instance
},

// v1
onshow: function(ctx, selectedData) {
ctx;
},

// v2
onshow: function(selectedData) {
this;
}
}

zoom.enabled.type interface updates

To simply and align with other interaction options format, moved the type field from being member of ‘enabled’ to member of ‘zoom’.

// v1.x
zoom: {
enabled: {
type: "drag"
}
}

// v2
zoom: {
enabled: true,
type: "drag" // if omit, 'wheel' will set by default
}

// There's no need to update if 'wheel' zoom type is used
// v1.x
zoom: {
enabled: true
}

// v2
zoom: {
enabled: true
}

deprecation of .transform() API

As anticipated by #801, removed the .transform() API. If you’re using it try by replacing same behavior vi .load().

for ESM import use cases only (not for UMD)

As describe above, to get benefits of bundle size cut, need to update your generation code by importing chart types and interaction modules.

https://github.com/naver/billboard.js/wiki/Migration-Guide-to-v2#3-update-your-esm-imports

What’s Next?

For the next stage, will focus to stabilize v2 for some possible bugs or errors due to the major updates.

And as always, adding new features to bring an easiest way to visualize data and facilitate anyones needs.

Thanks to the community, and stay healthy during this pandemic era.
See you soon!

--

--