Build a bottom axis


In the previous lesson we learnt how to manage margins efficiently on our chart.

Now, let's see how we can actually create a component that draws a bottom axis!

Wip
4 minutes read

Re-usable Bottom Axis component

The code snippet below builds a AxisBottom component. It is very much inspired from this blogpost by Amelia Wattenberger. I've just changed a few things, notably passing a scale as input instead of a range and a domain.

The logic mainly relies on the ticks() method of a d3 scale. It takes a target number of ticks as input, find the most appropriate way to build smart ticks based on this target, and returns an array with all the tick positions.

What follows is just some svg drawings based on those tick positions.

const TICK_LENGTH = 6;

export const AxisBottom = ({ xScale, pixelsPerTick }) => {
  const range = xScale.range();

  const ticks = useMemo(() => {
    const width = range[1] - range[0];
    const numberOfTicksTarget = Math.floor(width / pixelsPerTick);

    return xScale.ticks(numberOfTicksTarget).map((value) => ({
      value,
      xOffset: xScale(value),
    }));
  }, [xScale]);

  return (
    <>
      {/* Main horizontal line */}
      <path
        d={["M", range[0], 0, "L", range[1], 0].join(" ")}
        fill="none"
        stroke="currentColor"
      />

      {/* Ticks and labels */}
      {ticks.map(({ value, xOffset }) => (
        <g key={value} transform={`translate(${xOffset}, 0)`}>
          <line y2={TICK_LENGTH} stroke="currentColor" />
          <text
            key={value}
            style={{
              fontSize: "10px",
              textAnchor: "middle",
              transform: "translateY(20px)",
            }}
          >
            {value}
          </text>
        </g>
      ))}
    </>
  );
};

Using the component

Once you have the bottom and left axis component described above you just need to call them properly. You need to compute the bounds area by substracting the margins to the total svg area.

Don't forget to add an additional translation to the bottom axis to render it... at the bottom.

0246810

This axis is rendered without using d3.js to render.