Try / Rough.js in Y minutes

Rough.js is a small (<9KB gzipped) graphics library that lets you draw in a sketchy, hand-drawn style. The library defines primitives for lines, curves, arcs, polygons, circles, and ellipses. Rough.js works with both Canvas and SVG.

Let's see Rough.js in action! You can edit the code at any time and click the Run button to see the updated drawing.

Basic usage · Shapes · Filling · Sketching style · Further reading

✨ This is an open source guide. Feel free to improve it!

Basic usage

You can draw on a canvas:

// `out-canvas` is a `canvas` tag
// defined below this code snippet
const canvas = document.getElementById("out-canvas");

// clear the canvas for redrawing
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);

// draw a rectangle
const rc = rough.canvas(canvas);
rc.rectangle(20, 20, 200, 100); // x, y, width, height

// show the drawing
canvas.style.display = "block";

Or generate an svg:

// `out-svg` is an `svg` tag
// defined below this code snippet
const svg = document.getElementById("out-svg");

// clear the svg for redrawing
svg.innerHTML = "";

// draw a rectangle
const rs = rough.svg(svg);
const node = rs.rectangle(20, 20, 200, 100); // x, y, width, height

// show the drawing
svg.appendChild(node);
svg.style.display = "block";

Both RoughCanvas (an object returned by rough.canvas) and RoughSVG (an object returned by rough.svg) provide the same methods. The difference is that the RoughSVG methods return a node (g) that can be inserted into the SVG DOM.

I will be using RoughCanvas from now on.

Shapes

Draw a line from (x1, y1) to (x2, y2):

// `init` is a helper function I'm using in the examples.
// It initializes a RoughCanvas on the element with the given ID
// just like we did above.
const rc = init("c01");

rc.line(20, 20, 160, 60);
rc.line(20, 40, 160, 80, { strokeWidth: 5 });

Draw a rectangle with the top-left corner at (x, y) and the specified width and height:

const rc = init("c02");

rc.rectangle(20, 20, 100, 50);
rc.rectangle(140, 20, 100, 50, { fill: "red" });

Draw a circle with the center at (x, y) and the specified diameter:

const rc = init("c03");

rc.circle(60, 60, 80);

Draw an ellipse with the center at (x, y) and the specified width and height:

const rc = init("c04");

rc.ellipse(70, 50, 100, 60);
rc.ellipse(190, 50, 100, 60, { fill: "blue", stroke: "red" });

Draw a set of lines connecting the specified points:

const rc = init("c05");

// linearPath accepts an array of points.
// Each point is an array with values [x, y].
rc.linearPath([
    [20, 70],
    [70, 20],
    [120, 70],
    [170, 20],
    [220, 70],
]);

Draw a polygon with the specified vertices:

const rc = init("c06");

// polygon accepts an array of points.
// Each point is an array with values [x, y].
rc.polygon([
    [20, 70],
    [70, 20],
    [120, 50],
    [170, 20],
    [220, 70],
]);

Draw an arc:

// An arc is described as a section of an ellipse.
arc(x, y, width, height, start, stop, closed [, options]) {}
// x, y          - the center of the ellipse.
// width, height - the dimensions of the ellipse.
// start, stop   - the start and stop angles for the arc.
//
// closed is a boolean.
// If true, the end points of the arc will be connected to the center.
const rc = init("c07");

// upper left segment
rc.arc(70, 60, 100, 80, Math.PI, Math.PI * 1.6, true);

// lower right segment
rc.arc(70, 60, 100, 80, 0, Math.PI / 2, true, {
    stroke: "red",
    strokeWidth: 4,
    fill: "rgba(255,255,0,0.4)",
    fillStyle: "solid",
});

// lower left segment
rc.arc(70, 60, 100, 80, Math.PI / 2, Math.PI, true, {
    stroke: "blue",
    strokeWidth: 2,
    fill: "rgba(255,0,255,0.4)",
});

Draw a curve passing through the points:

const rc = init("c08");

// curve accepts an array of points.
// Each point is an array with values [x, y].
rc.curve([
    [20, 70],
    [70, 20],
    [120, 70],
    [170, 20],
    [220, 70],
]);

Draw a path described by an SVG path data string:

const rc = init("c09");

rc.path("M 20 70 C 50 0, 75 0, 105 70 S 160 140, 190 70", {
    stroke: "blue",
    fill: "green",
});

Write some text using the Canvas API:

const rc = init("c10");

// draw two rectangles and an arrow
rc.rectangle(20, 20, 100, 50);
rc.rectangle(220, 20, 100, 50);
rc.line(120, 45, 220, 45);
rc.line(220, 45, 200, 40);
rc.line(220, 45, 200, 50);

// write some text
const ctx = rc.canvas.getContext("2d");
ctx.font = "16px sans-serif";
ctx.fillStyle = "blue";
ctx.fillText("Rough.js", 40, 50);
ctx.fillText("is", 160, 40);
ctx.fillText("awesome", 235, 50);

Filling

The fill property specifies the color used to fill a shape. Uses hachure by default:

const rc = init("c11");

rc.circle(60, 60, 80, { fill: "red" });
rc.rectangle(120, 20, 80, 80, { fill: "red" });

You can change the hatch angle and line thickness, or choose a different fill style altogether:

const rc = init("c12");

// hatch angle
rc.rectangle(20, 20, 80, 80, {
    fill: "red",
    hachureAngle: 60,
    hachureGap: 8,
});

// thicker lines
rc.circle(160, 60, 80, {
    fill: "rgb(10,150,10)",
    fillWeight: 3,
});

// solid fill instead of hachure
rc.rectangle(220, 20, 80, 80, {
    fill: "rgba(255,0,200,0.2)",
    fillStyle: "solid",
});

You can use the following fill styles:

const rc = init("c13");

// hachure (default) draws sketchy parallel lines.
rc.rectangle(20, 20, 80, 80, {
    fill: "blue",
});

// solid is more like a conventional fill.
rc.rectangle(120, 20, 80, 80, {
    fillStyle: "solid",
    fill: "blue",
});

// zigzag draws zigzag lines that fill the shape.
rc.rectangle(220, 20, 80, 80, {
    fillStyle: "zigzag",
    fill: "blue",
});

// cross-hatch is similar to hachure, but draws cross-hatched lines.
rc.rectangle(320, 20, 80, 80, {
    fillStyle: "cross-hatch",
    fill: "blue",
});

And even more:

const rc = init("c14");

// dots fills the shape with sketchy dots.
rc.rectangle(20, 20, 80, 80, {
    fillStyle: "dots",
    fill: "blue",
});

// dashed is similar to hachure, but the lines are dashed.
rc.rectangle(120, 20, 80, 80, {
    fillStyle: "dashed",
    fill: "blue",
    dashOffset: 5,
    dashGap: 5,
});

// zigzag-line is similar to hachure,
// but the lines are drawn in a zigzag pattern.
rc.rectangle(220, 20, 80, 80, {
    fillStyle: "zigzag-line",
    fill: "blue",
    zigzagOffset: 3,
});

Sketching style

You can control the roughness of the drawing:

const rc = init("c21");

// A rectangle with the roughness of 0 would be a perfect rectangle.
rc.rectangle(20, 20, 80, 80, {
    roughness: 0,
    fill: "red",
});

// The default value is 1.
rc.rectangle(120, 20, 80, 80, {
    roughness: 1,
    fill: "blue",
});

// There is no upper limit to this value.
rc.rectangle(220, 20, 80, 80, {
    roughness: 3,
    fill: "green",
});

// But a value over 10 is mostly useless.
rc.rectangle(320, 20, 80, 80, {
    roughness: 5,
    fill: "gold",
});

You can also control bowing:

const rc = init("c22");

// Bowing indicates how curvy the lines are.
// A value of 0 will cause straight lines.
rc.rectangle(20, 20, 80, 80, {
    bowing: 0,
    fill: "red",
});

// The default value is 1.
rc.rectangle(120, 20, 80, 80, {
    bowing: 1,
    fill: "blue",
});

// There is no upper limit to this value.
rc.rectangle(220, 20, 80, 80, {
    bowing: 8,
    fill: "green",
});

// But a value over 20 is mostly useless.
rc.rectangle(320, 20, 80, 80, {
    bowing: 20,
    fill: "gold",
});

Further reading

Rough.js also supports other configuration options. See the documentation for details.

See the project page to start using Rough.js on your website or in your product.

Preet Shihn + 1 others · original · CC-BY-SA-4.0 · 2024-02-24