Login With Github

RoughJS Examples

In this chapter,you can get some basic examples and advanced examples with RoughJS.Code is available in the examples folder in Github.

Simple showcase of most features

Work with Canvas

Code:

<canvas id="canvas" width="800" height="600"></canvas>
<script>
const rc = rough.canvas(document.getElementById('canvas'));

//line and rectangle
rc.rectangle(10, 10, 100, 100);
rc.rectangle(140, 10, 100, 100, {
  fill: 'rgba(255,0,0,0.2)',
  fillStyle: 'solid',
  roughness: 2
});
rc.rectangle(10, 130, 100, 100, {
  fill: 'red',
  stroke: 'blue',
  hachureAngle: 60,
  hachureGap: 10,
  fillWeight: 5,
  strokeWidth: 5
});

// ellipse and circle
rc.ellipse(350, 50, 150, 80);
rc.ellipse(610, 50, 150, 80, {
  fill: 'blue'
});
rc.circle(480, 50, 80, {
  stroke: 'red', strokeWidth: 2,
  fill: 'rgba(0,255,0,0.3)', fillStyle: 'solid'
});

//overlapping circles
rc.circle(480, 150, 80, {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(0,255,0,1)', fillWeight: 4, hachureGap: 6
});
rc.circle(530, 150, 80, {
  stroke: 'blue', strokeWidth: 4,
  fill: 'rgba(255,255,0,1)', fillWeight: 4, hachureGap: 6
});

// linearPath and polygon
rc.linearPath([[690, 10], [790, 20], [750, 120], [690, 100]], {
  roughness: 0.7,
  stroke: 'red', strokeWidth: 4
});
rc.polygon([[690, 130], [790, 140], [750, 240], [690, 220]]);
rc.polygon([[690, 250], [790, 260], [750, 360], [690, 340]], {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(0,0,255,0.2)', fillStyle: 'solid'
});
rc.polygon([[690, 370], [790, 385], [750, 480], [690, 460]], {
  stroke: 'red',
  hachureAngle: 65,
  fill: 'rgba(0,0,255,0.6)'
});

// arcs
rc.arc(350, 200, 200, 180, Math.PI, Math.PI * 1.6);
rc.arc(350, 300, 200, 180, Math.PI, Math.PI * 1.6, true);
rc.arc(350, 300, 200, 180, 0, Math.PI / 2, true, {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(255,255,0,0.4)', fillStyle: 'solid'
});
rc.arc(350, 300, 200, 180, Math.PI / 2, Math.PI, true, {
  stroke: 'blue', strokeWidth: 2,
  fill: 'rgba(255,0,255,0.4)'
});

// draw sine curve
let points = [];
for (let i = 0; i < 20; i++) {
  // 4pi - 400px
  let x = (400 / 20) * i + 10;
  let xdeg = (Math.PI / 100) * x;
  let y = Math.round(Math.sin(xdeg) * 90) + 500;
  points.push([x, y]);
}
rc.curve(points, {
  roughness: 1.2, stroke: 'red', strokeWidth: 3
});
</script>

View Demo

Work with SVG

Code:

<svg id="svg"></svg>
<script>
const svg = document.getElementById('svg');
const rc = rough.svg(svg);

//line and rectangle
svg.appendChild(rc.line(60, 60, 190, 60));
svg.appendChild(rc.rectangle(10, 10, 100, 100));
svg.appendChild(rc.rectangle(140, 10, 100, 100, {
  fill: 'rgba(255,0,0,0.2)',
  fillStyle: 'solid',
  roughness: 2
}));
svg.appendChild(rc.rectangle(10, 130, 100, 100, {
  fill: 'red',
  stroke: 'blue',
  hachureAngle: 60,
  hachureGap: 10,
  fillWeight: 5,
  strokeWidth: 5
}));


// ellipse and circle
svg.appendChild(rc.ellipse(350, 50, 150, 80));
svg.appendChild(rc.ellipse(610, 50, 150, 80, {
  fill: 'blue'
}));
svg.appendChild(rc.circle(480, 50, 80, {
  stroke: 'red', strokeWidth: 2,
  fill: 'rgba(0,255,0,0.3)', fillStyle: 'solid'
}));

//overlapping circles
svg.appendChild(rc.circle(480, 150, 80, {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(0,255,0,1)', fillWeight: 4, hachureGap: 6
}));
svg.appendChild(rc.circle(530, 150, 80, {
  stroke: 'blue', strokeWidth: 4,
  fill: 'rgba(255,255,0,1)', fillWeight: 4, hachureGap: 6
}));

// linearPath and polygon
svg.appendChild(rc.linearPath([[690, 10], [790, 20], [750, 120], [690, 100]], {
  roughness: 0.7,
  stroke: 'red', strokeWidth: 4
}));
svg.appendChild(rc.polygon([[690, 130], [790, 140], [750, 240], [690, 220]]));
svg.appendChild(rc.polygon([[690, 250], [790, 260], [750, 360], [690, 340]], {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(0,0,255,0.2)', fillStyle: 'solid'
}));
svg.appendChild(rc.polygon([[690, 370], [790, 385], [750, 480], [690, 460]], {
  stroke: 'red',
  hachureAngle: 65,
  fill: 'rgba(0,0,255,0.6)'
}));


// arcs
svg.appendChild(rc.arc(350, 200, 200, 180, Math.PI, Math.PI * 1.6));
svg.appendChild(rc.arc(350, 300, 200, 180, Math.PI, Math.PI * 1.6, true));
svg.appendChild(rc.arc(350, 300, 200, 180, 0, Math.PI / 2, true, {
  stroke: 'red', strokeWidth: 4,
  fill: 'rgba(255,255,0,0.4)', fillStyle: 'solid'
}));
svg.appendChild(rc.arc(350, 300, 200, 180, Math.PI / 2, Math.PI, true, {
  stroke: 'blue', strokeWidth: 2,
  fill: 'rgba(255,0,255,0.4)'
}));

// draw sine curve
let points = [];
for (let i = 0; i < 20; i++) {
  // 4pi - 400px
  let x = (400 / 20) * i + 10;
  let xdeg = (Math.PI / 100) * x;
  let y = Math.round(Math.sin(xdeg) * 90) + 500;
  points.push([x, y]);
}
svg.appendChild(rc.curve(points, {
  roughness: 1.2, stroke: 'red', strokeWidth: 3
}));
</script>

View Demo

Using SVG Paths

Work with Canvas

Code:

<canvas id="canvas" width="800" height="600"></canvas>
<script>
const rc = rough.canvas(document.getElementById('canvas'));
rc.path('M400 100 h 90 v 90 h -90z', {
  stroke: 'red',
  strokeWidth: '3',
  fill: 'rgba(0,0,255,0.2)',
  fillStyle: 'solid'
});
rc.path('M400 250 h 90 v 90 h -90z', {
  fill: 'rgba(0,0,255,0.6)'
});
rc.path('M37,17v15H14V17z M50,5H5v50h45z', {
  stroke: 'red',
  strokeWidth: '1',
  fill: 'blue'
});
rc.path('M80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z', { fill: 'green' });
rc.path('M230 80 A 45 45, 0, 1, 0, 275 125 L 275 80 Z', { fill: 'purple', hachureAngle: 60, hachureGap: 5 });
rc.path('M80 230 A 45 45, 0, 0, 1, 125 275 L 125 230 Z', { fill: 'red' });
rc.path('M230 230 A 45 45, 0, 1, 1, 275 275 L 275 230 Z', { fill: 'blue' });
</script>

View Demo

Work with SVG

Code:

<svg id="svg"></svg>
<script>
const svg = document.getElementById('svg');
const rc = rough.svg(svg);

svg.appendChild(rc.path('M400 100 h 90 v 90 h -90z', {
  stroke: 'red',
  strokeWidth: '3',
  fill: 'rgba(0,0,255,0.2)',
  fillStyle: 'solid'
}));
svg.appendChild(rc.path('M400 250 h 90 v 90 h -90z', {
  fill: 'rgba(0,0,255,0.6)',
  fillWeight: 4, hachureGap: 8
}));
svg.appendChild(rc.path('M37,17v15H14V17z M50,0H0v50h50z', {
  stroke: 'red',
  strokeWidth: '1',
  fill: 'blue'
}));
svg.appendChild(rc.path('M80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z', { fill: 'green' }));
svg.appendChild(rc.path('M230 80 A 45 45, 0, 1, 0, 275 125 L 275 80 Z', { fill: 'purple', hachureAngle: 60, hachureGap: 5 }));
svg.appendChild(rc.path('M80 230 A 45 45, 0, 0, 1, 125 275 L 125 230 Z', { fill: 'red' }));
svg.appendChild(rc.path('M230 230 A 45 45, 0, 1, 1, 275 275 L 275 230 Z', { fill: 'blue' }));
</script>

View Demo

Bar Chart - Using D3

Code:

<script src="rough.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<canvas id="canvas" width="960" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas');
const rc = rough.canvas(canvas, {
  options: {
	fill: "blue",
	roughness: 0.8,
	bowing: 0.7
  }
});

var context = canvas.getContext("2d");
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
  width = canvas.width - margin.left - margin.right,
  height = canvas.height - margin.top - margin.bottom;
var x = d3.scaleBand()
  .rangeRound([0, width])
  .padding(0.1);
var y = d3.scaleLinear()
  .rangeRound([height, 0]);
context.translate(margin.left, margin.top);

d3.tsv("data.tsv", function (d) {
  d.frequency = +d.frequency;
  return d;
}, function (error, data) {
  if (error) throw error;

  x.domain(data.map(function (d) { return d.letter; }));
  y.domain([0, d3.max(data, function (d) { return d.frequency; })]);

  var yTickCount = 10,
	yTicks = y.ticks(yTickCount),
	yTickFormat = y.tickFormat(yTickCount, "%");

  data.forEach(function (d) {
	rc.rectangle(x(d.letter), y(d.frequency), x.bandwidth(), height - y(d.frequency));
  });


  context.beginPath();
  x.domain().forEach(function (d) {
	context.moveTo(x(d) + x.bandwidth() / 2, height);
	context.lineTo(x(d) + x.bandwidth() / 2, height + 6);
  });
  context.strokeStyle = "black";
  context.stroke();

  context.textAlign = "center";
  context.textBaseline = "top";
  x.domain().forEach(function (d) {
	context.fillText(d, x(d) + x.bandwidth() / 2, height + 6);
  });

  context.beginPath();
  yTicks.forEach(function (d) {
	context.moveTo(0, y(d) + 0.5);
	context.lineTo(-6, y(d) + 0.5);
  });
  context.strokeStyle = "black";
  context.stroke();

  context.textAlign = "right";
  context.textBaseline = "middle";
  yTicks.forEach(function (d) {
	context.fillText(yTickFormat(d), -9, y(d));
  });

  context.beginPath();
  context.moveTo(-6.5, 0 + 0.5);
  context.lineTo(0.5, 0 + 0.5);
  context.lineTo(0.5, height + 0.5);
  context.lineTo(-6.5, height + 0.5);
  context.strokeStyle = "black";
  context.stroke();

  context.save();
  context.rotate(-Math.PI / 2);
  context.textAlign = "right";
  context.textBaseline = "top";
  context.font = "bold 10px sans-serif";
  context.fillText("Frequency", -10, 10);
  context.restore();
});
</script>

View Demo

US Map - Using D3 and Web Workers

Work with Canvas

Code:

<script src="workly.min.js"></script>
<script src="rough.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<canvas id="canvas" width="960" height="500"></canvas>
<script>
const rc = rough.canvas(document.getElementById('canvas'), {
  async: true,
  options: {
	simplification: 0.2, roughness: 0.65
  }
});
const width = 960, height = 500;
const projection = d3.geo.albersUsa().scale(1070).translate([width / 2, height / 2]);
const path = d3.geo.path().projection(projection);
const randomColor = () => {
  let r = `rgb(${Math.round(Math.random() * 255)}, ${Math.round(Math.random() * 255)}, ${Math.round(Math.random() * 255)})`;
  return r;
}
const randomAngle = () => {
  return (Math.random() > 0.5 ? -1 : 1) * (1 + Math.random() * 88);
}
const randomStyle = () => {
  return (Math.random() > 0.5 ? 'solid' : '');
}
d3.json("./us.json", async (error, us) => {
  if (error) throw error;
  let topo = topojson.feature(us, us.objects.states).features;
  for (let feature of topo) {
	rc.path(path(feature), {
	  fill: randomColor(),
	  fillStyle: randomStyle(),
	  hachureAngle: randomAngle()
	});
  }
});
</script>

View Demo

Work with SVG

Code:

<svg id="svg"></svg>
<script>
const svg = document.getElementById('svg');
const rc = rough.svg(svg, {
  async: true,
  options: {
	simplification: 0.2, roughness: 0.65
  }
});
const width = 960, height = 500;
const projection = d3.geo.albersUsa().scale(1070).translate([width / 2, height / 2]);
const path = d3.geo.path().projection(projection);
const randomColor = () => {
  let r = `rgb(${Math.round(Math.random() * 255)}, ${Math.round(Math.random() * 255)}, ${Math.round(Math.random() * 255)})`;
  return r;
}
const randomAngle = () => {
  return (Math.random() > 0.5 ? -1 : 1) * (1 + Math.random() * 88);
}
const randomStyle = () => {
  return (Math.random() > 0.5 ? 'solid' : '');
}
d3.json("./us.json", async (error, us) => {
  if (error) throw error;
  let topo = topojson.feature(us, us.objects.states).features;
  for (let feature of topo) {
	svg.appendChild(await rc.path(path(feature), {
	  fill: randomColor(),
	  fillStyle: randomStyle(),
	  hachureAngle: randomAngle()
	}));
  }
});
</script>

View Demo

Generators

Simple example using generators to create shapes and then redrawing them.

<canvas id="canvas" width="800" height="600"></canvas>
<script>
const rc = rough.canvas(document.getElementById('canvas'));
const generator = rc.generator;
const ctx = document.getElementById('canvas').getContext('2d');

const rectangles = [
  generator.rectangle(10, 10, 100, 100),
  generator.rectangle(140, 10, 100, 100, { fill: 'rgba(255,0,0,0.2)', fillStyle: 'solid', roughness: 2 }),
  generator.rectangle(10, 130, 100, 100, {
	fill: 'red',
	stroke: 'blue',
	hachureAngle: 60,
	hachureGap: 10,
	fillWeight: 5,
	strokeWidth: 5
  })
];

function redraw() {
  ctx.clearRect(0, 0, 800, 600);
  setTimeout(() => {
	for (const r of rectangles) {
	  rc.draw(r);
	}
  }, 100);
}

redraw();
</script>

View Demo

Animated Balloons

Code:

<script>
const extend = (base, ...extensions) => Object.assign({}, base, ...extensions)

const parseColor = ({ h, s, l, a }) => `hsla(${h},${s}%,${l}%,${a})`

const Color = extend.bind(null, { h: 0, s: 100, l: 100, a: 1 })

const Vector = extend.bind(null, { x: 0, y: 0 })

const Particle = extend.bind(null, {
  pos: Vector(),
  vel: Vector(),
  angle: 0,
  speed: 0,
  radius: 0,
  rotation: 0,
  color: Color()
})

const colors = [
  Color({ h: 20, s: 100, l: 50 }),
  Color({ h: 200, l: 50 }),
  Color({ h: 300, l: 50 }),
  Color({ h: 100, l: 40 }),
]

const animationLoop = scope => {
  if (scope.animation) {
	scope.animation(animationLoop.bind(null, scope))
  }

  const { ctx } = scope
  const { canvas } = ctx
  const rc = rough.canvas(canvas)
  ctx.clearRect(0, 0, canvas.width, canvas.height)

  scope.particles.map((p, i) => {
	p.pos.y -= p.speed
	if (i % 2) {
	  p.pos.x = p.pos.x + Math.sin(p.angle) * .2
	} else {
	  p.pos.x = p.pos.x - Math.cos(p.angle) * .2
	}
	p.angle += .01
	rc.circle(p.pos.x, p.pos.y, p.radius, {
	  fill: parseColor(p.color),
	  roughness: Math.random() * 1.5,
	  hachureGap: p.hachureGap,
	  hachureAngle: p.hachureAngle
	})
	rc.line(p.pos.x, p.pos.y + p.radius * 1.2, p.pos.x, p.pos.y + p.radius / 2, {
	  bowing: Math.random() * 3
	})
	if (p.pos.y + p.radius * 3 < 0) {
	  p.pos.y = canvas.height + p.radius * 3
	  p.pos.x = Math.random() * (canvas.width - p.radius)
	}
  })
}

const scope = {
  animation: requestAnimationFrame.bind(null),
  ctx: document.createElement('canvas').getContext('2d'),
  rotation: 0,
  particles: []
}

~(scope => {
  const { ctx: { canvas } } = scope

  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  document.body.appendChild(canvas)

  let particleCount = 60
  while (particleCount--) {
	scope.particles.push(Particle({
	  pos: {
		x: Math.random() * canvas.width,
		y: Math.random() * canvas.height
	  },
	  speed: Math.random() + .2,
	  radius: Math.random() * 60 + 20,
	  color: colors[Math.floor(Math.random() * colors.length)],
	  hachureAngle: Math.random() * 90,
	  hachureGap: Math.random() * 8
	}))
  }

  animationLoop(scope)
})(scope)
</script>

View Demo

Rough with Matter.js

Code:

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.js"></script>
<script src="../rough.min.js"></script>
<canvas id="can" width="800px" height="500px"></canvas>
<script>
   var Engine = Matter.Engine,
       Render = Matter.Render,
       World = Matter.World,
       Bodies = Matter.Bodies,
       Body = Matter.Body,
       Vec = Matter.Vector;
   deg = Math.PI / 180;
   var engine = Engine.create();

   var render = Render.create({
       element: document.body,
       engine: engine,
       options: {
           width: 800,
           height: 500,
           wireframes: false
       }
   });

   var boxA = Bodies.rectangle(400, 200, 80, 80);
   var ballA = Bodies.circle(380, 100, 40, 10);
   var ballB = Bodies.circle(460, 10, 60, 10);
   var triA = Bodies.polygon(350, 200, 3, 50)
   var ground = Bodies.rectangle(400, 380, 500, 60, {
       isStatic: true
   });
   ballA.restitution = 0.8;
   ballB.restitution = 0.8;
   triA.restitution = 0.6;
   triA.friction = 0.01;
   boxA.restitution = 0.6;
   boxA.friction = 0.01;
   ballB.friction = 1;
   ballA.friction = 1;
   Body.rotate(boxA, 20 * deg);

   World.add(engine.world, [boxA, ballA, ballB, ground, triA]);

   Engine.run(engine);



   canvas = document.getElementById("can");
   ctx = canvas.getContext("2d");
   let cvs = rough.canvas(canvas);


   setInterval(function() {

       ctx.clearRect(0, 0, 800, 800);
       cvs.circle(ballA.position.x, ballA.position.y, 80, {
           fill: "#0000ff",
           roughness: 1
       });

       cvs.circle(ballB.position.x, ballB.position.y, 120, {
           fill: "#00ff00",
           roughness: 1
       });



       cvs.polygon(ground.vertices.map(x => [x.x, x.y]), {
           fill: "#000000",
           roughness: 0.5
       });


       cvs.polygon(triA.vertices.map(x => [x.x, x.y]), {
           fill: "#ff00ff",
           roughness: 1
       });

       cvs.polygon(boxA.vertices.map(x => [x.x, x.y]), {
           fill: "#ff0000",
           roughness: 1
       });




   }, 20)


   function rand(min, max) {
       return Math.floor(Math.random() * (max - min + 1)) + min;
   }



   setInterval(function() {
       Body.setPosition(boxA, (Vec.create(400, 200)))
       Body.setPosition(ballA, (Vec.create(380, 100)));
       Body.setPosition(ballB, (Vec.create(460, 60)))
       Body.setPosition(triA, (Vec.create(300, 200)))

       Body.setVelocity(ballB, (Vec.create(rand(-10, 10), rand(-10, 10))))
       Body.setVelocity(ballA, (Vec.create(rand(-10, 10), rand(-10, 10))))
       Body.setVelocity(boxA, (Vec.create(rand(-10, 10), rand(-10, 10))))

       Body.setVelocity(triA, (Vec.create(rand(-10, 10), rand(-10, 10))))

   }, 4000)
</script>

View Demo

Other projects using RoughJS

Description Link
wired-elements common ui web components with hand-drawn look wiredjs.com
Semiotic - a data visualization framework for React by Elijah Meeks uses rough.js for sketchy rendering View
A rough plugin for Leaflet View
Snake game by @AriaFallah View
React components for RoughJS View
Livegap - Online charts with sketchy rendering View

0 Comment

temp