beautiful or else.
bore is a library built on top of D3 that lets you create extendible, reusable and stylistically consistent visualizations. It follows from the article "Towards Reusable Charts" written by Mike Bostock.
We use it for our data graphics at The Michigan Daily.
If you're familiar with D3, using bore should be fairly intuitive because it follows from the function pattern in D3 (and jQuery).
const svg = d3.select("figure")
.append("svg")
.attr("width", width)
.attr("height", height);
const x = d3.scaleLinear()
.domain([0, 100])
.range([margin.left, width - margin.right])
const xAxis = svg.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3.axisLeft(x).ticks(width / 80));Here we append a g element to the svg and call the axisLeft function with the x scale. We chain the ticks function to modify the default behavior of the axis function.
The purpose of bore is to create a higher-level API on top of D3 that can be used to create common chart types. Like how D3 has a built-in API for creating axes, bore has a built-in API for creating charts.
In addition to providing chart types, bore also exports several useful utility constructs such as a text-wrapping, styled axes and color schemes.
-
Add
boreas a dependency:yarn add michigandaily/bore
You can use a specific version or branch of
boreby adding a#to the end and specifying a version or branch (e.g.,#v3.0.1). -
Import
bore:import * as bore from "@michigandaily/bore";
-
Bind your data to an SVG:
const svg = d3.select("figure") .append("svg") .datum(data);
This library is being made with maps* in mind, but it may also work with other iterables.
-
Call a
borechart on your SVG selection:svg.call( bore.build( new bore.BarChart() .color(color) .height(175) .label(d => `${d[1].toPrecision(3)}%`) .wrappx(75) ) );
Make note of the
newkeyword. Internally,boreimplements each chart type as a class. Thenewkeyword is necessary to create a new instance of a class (as is usual in OOP).Also make note of the
buildfunction that wraps the entireBarChartconstruction. Internally, this is necessary to correctly bind thethiscontext of the chart to itself instead of to the D3 selection.Using other chart types will follow a nearly identical pattern, though the functions that can be chained to a chart type may differ from chart to chart. Refer to the API Reference for more details or take a look at the examples.
* I initially chose maps over objects because I felt it'd be less ergonomic to have to specify an x or y accessor. However, it may be preferable to specify accessors in some chart types. I have not done research into the performance benefits of maps or objects.
TODO
Work on a branch if you plan on adding something to bore -- the main branch is protected.
- Clone
cookieandboreinto the same directory. - Run
yarn installincookieand inbore.
-
In
bore, runyarn link. -
In
cookie, runyarn link "@michigandaily/bore". -
Import
boreincookie:// cookie/src/graphic/js/graphic.js import * as bore from "@michigandaily/bore";
In cookie, run yarn dev.
Whenever changes are made in bore, the cookie server will reload to reflect those changes.
When finished developing, unlink the repositories.
- In
cookie, runyarn unlink "@michigandaily/bore". - In
bore, runyarn unlink.
- Update the version in
package.jsonaccording to semantic versioning. - Create a pull request to
main. - Once merged, create a new tag and release with the same version number in
package.jsonprefxied withv.