Categories
Visx

Add Marker Icons onto Lines with the Visx Library

Spread the love

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add a line with markers into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/curve @visx/glyph @visx/group @visx/mock-data @visx/responsive @visx/scale @visx/shape

to install the packages.

Create Lines with Markers

We can create lines with markers with the @visx/glyph module to add the markers.

To do this, we write:

import React from "react";
import { Group } from "@visx/group";
import {
  Glyph as CustomGlyph,
  GlyphCircle,
  GlyphCross,
  GlyphDiamond,
  GlyphSquare,
  GlyphStar,
  GlyphTriangle,
  GlyphWye
} from "@visx/glyph";
import { LinePath } from "@visx/shape";
import genDateValue from "@visx/mock-data/lib/generators/genDateValue";
import { scaleTime, scaleLinear } from "@visx/scale";
import { curveMonotoneX, curveBasis } from "@visx/curve";

const defaultMargin = { top: 10, right: 10, bottom: 10, left: 10 };

export const primaryColor = "#8921e0";
export const secondaryColor = "#00f2ff";
const contrastColor = "#ffffff";

const Glyphs = [
  GlyphCircle,
  GlyphCross,
  GlyphDiamond,
  GlyphStar,
  GlyphTriangle,
  GlyphSquare,
  GlyphWye,
  ({ left, top }) => (
    <CustomGlyph left={left} top={top}>
      <circle r={12} fill={secondaryColor} />
      <text fontSize={16} textAnchor="middle" dy="0.5em">
        {"?"}
      </text>
    </CustomGlyph>
  )
];

const data = genDateValue(Glyphs.length * 2);

const date = (d) => d.date.valueOf();
const value = (d) => d.value;

const xScale = scaleTime({
  domain: [Math.min(...data.map(date)), Math.max(...data.map(date))]
});
const yScale = scaleLinear({
  domain: [0, Math.max(...data.map(value))]
});

const getX = (d) => xScale(date(d)) ?? 0;
const getY = (d) => yScale(value(d)) ?? 0;

function Example({ width, height, margin = defaultMargin }) {
  if (width < 10) return null;
  const innerWidth = width - margin.left - margin.right;
  const innerHeight = height - margin.top - margin.bottom;
  xScale.range([0, innerWidth]);
  yScale.range([innerHeight, 0]);

return (
    <svg width={width} height={height}>
      <rect
        x={0}
        y={0}
        width={width}
        height={height}
        fill={secondaryColor}
        rx={14}
      />
      <Group left={margin.left} top={margin.top}>
        <LinePath
          data={data}
          x={getX}
          y={getY}
          stroke={primaryColor}
          strokeWidth={2}
          strokeDasharray="2,2"
          curve={curveBasis}
        />
        <LinePath
          data={data}
          x={getX}
          y={getY}
          stroke={primaryColor}
          strokeWidth={2}
          curve={curveMonotoneX}
        />
        {data.map((d, i) => {
          const CurrGlyph = Glyphs[i % Glyphs.length];
          const left = getX(d);
          const top = getY(d);
          return (
            <g key={`line-glyph-${i}`}>
              <CurrGlyph
                left={left}
                top={top}
                size={110}
                stroke={secondaryColor}
                strokeWidth={10}
              />
              <CurrGlyph
                left={left}
                top={top}
                size={110}
                fill={i % 2 === 0 ? primaryColor : contrastColor}
                stroke={i % 2 === 0 ? contrastColor : primaryColor}
                strokeWidth={2}
              />
            </g>
          );
        })}
      </Group>
    </svg>
  );
}

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

We add the margins for the graph with the defaultMargin variable.

primaryColor , secondaryColor have the colors for the lines.

contrastColor have the background color for the markers.

The Glyphs array have the icons and a function that returns a custom component with the icon.

CustomGlyph takes the left and top properties to set its position.

data has the data for the line.

date and value are functions that return the value given the entry.

xScale has the scale for the x-axis.

And yScale has the scale for the y-axis.

The Example component is where we put the chart together.

We set the width and height of the chart with the innerWidth and innerHeight variables.

The Group component wraps around the parts of the chart.

LinePath has the lines for the graph.

We pass in the getX and getY functions to render the data as lines.

The first LinePath renders a dotted line.

And the 2nd one renders a solid line.

The markers are rendered with the data.map callback.

It returns the CurrGlyph components to render our marker.

We set the left and top props to set the position.

CurrGlyph is created from the Glyphs array by getting the icon to render by its index.

Now we should see 2 lines with markers for each.

Conclusion

We can create lines with markers easily in our React app with the Visx library.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *