Examples: basic barchart

Author

James Goldie

Published

June 2, 2023

Let’s start with a simple barchart.

This isn’t going to be one of those barcharts you’ve seen on TV, what with tick marks and hover effects and such. This one’s just some bars, some labels and a baseline. It will, however, come with some useful features to help us reuse it.

Try it out

The following code initialises our bar chart.

Code
BarChart =
  import("./../../examples/barchart/BarChart.js")

myBarChart = new BarChart.default({
  target: document.querySelector("#mybarchart"),
  props: {
    data: [5, 5, 5, 5, 5],
    height: 200,
    width: 200,
    barWidth: 25,
    barColor: "#36a7e9"
  }
});

See the bar chart source at BarChart.svelte

This Svelte component accepts a few props:

  • data: a simple array of (up to) 5 numbers
  • height: the height of the chart in pixels
  • width: the width of the chart in pixels
  • barWidth: the width of each bar
  • barColor: the colour of the bars and labels (note the US spelling here)

We can hook any of those values up to OJS code using myBarChart.propName.

Let’s give the user the choice between a randomly changing bar chart and user-configurable data and colours:

Code
viewof changeType = Inputs.radio(["Random", "Custom"], {value: "Random"})

Here’s how we generate data and colours that change every two seconds

Code
randomData = {
  while(true) {
    yield Promises.delay(2000, [
      Math.floor(Math.random() * 100).toString(),
      Math.floor(Math.random() * 100).toString(),
      Math.floor(Math.random() * 100).toString(),
      Math.floor(Math.random() * 100).toString(),
      Math.floor(Math.random() * 100).toString()
    ]);
  }
}

randomColor = {
  while(true) {
    yield Promises.delay(2000,
    `#${Math.floor(Math.random() * 256).toString(16)}${Math.floor(Math.random() * 256).toString(16)}${Math.floor(Math.random() * 256).toString(16)}`);
  }
}

And here are inputs that allow the user to change the data and colour:

Code
viewof userData = Inputs.form(
  [
    Inputs.text({type: "number", value: 25, width: 20}),
    Inputs.text({type: "number", value: 35, width: 20}),
    Inputs.text({type: "number", value: 65, width: 20}),
    Inputs.text({type: "number", value: 5, width: 20}),
    Inputs.text({type: "number", value: 50, width: 20})
  ], {
    disabled: changeType == "Random"
  });

viewof userColor = Inputs.color({
  value: "#36a7e9",
  disabled: changeType == "Random"});

Finally, we update the visual whenever either the choice type changes or the random data does:

Code
myBarChart.data = changeType == "Random" ? randomData : [...userData];
Code
myBarChart.barColor = changeType == "Random" ? randomColor : userColor;

Challenges

This Svelte component’s pretty basic, though. What else is it missing?

  • The height and width are configurable, and the bars resize in response to them, but their CSS transitions are slow to catch up. Ideally we’d have the bars apply the transition when they resize because of a change in data but not in response to a change in chart height or width.
  • We have no axes other than the baseline. That’s fine for a lot of uses, but we might want to add those elements for other uses.
    • We could add those elements manually, but the d3-axis package has some helpers for creating axes quickly!
  • The bars are all the same colour. We could write a function that converts each bar’s data value to a colour, and use it for the <rect> fill attribute, but the d3-scale-chromatic also has some helpers to do this quickly!