Giter Club home page Giter Club logo

rough's Introduction

Rough.js

Rough.js is a small (<9 kB) graphics library that lets you draw in a sketchy, hand-drawn-like, style. The library defines primitives to draw lines, curves, arcs, polygons, circles, and ellipses. It also supports drawing SVG paths.

Rough.js works with both Canvas and SVG.

Rough.js sample

@RoughLib on Twitter.

Install

from npm:

npm install --save roughjs

Or get the latest using unpkg: https://unpkg.com/roughjs@latest/bundled/rough.js

If you are looking for bundled version in different formats, the npm package will have these in the following locations:

CommonJS: roughjs/bundled/rough.cjs.js

ESM: roughjs/bundled/rough.esm.js

Browser IIFE: roughjs/bundled/rough.js

Usage

Rough.js rectangle

const rc = rough.canvas(document.getElementById('canvas'));
rc.rectangle(10, 10, 200, 200); // x, y, width, height

or SVG

const rc = rough.svg(svg);
let node = rc.rectangle(10, 10, 200, 200); // x, y, width, height
svg.appendChild(node);

Lines and Ellipses

Rough.js rectangle

rc.circle(80, 120, 50); // centerX, centerY, diameter
rc.ellipse(300, 100, 150, 80); // centerX, centerY, width, height
rc.line(80, 120, 300, 100); // x1, y1, x2, y2

Filling

Rough.js rectangle

rc.circle(50, 50, 80, { fill: 'red' }); // fill with red hachure
rc.rectangle(120, 15, 80, 80, { fill: 'red' });
rc.circle(50, 150, 80, {
  fill: "rgb(10,150,10)",
  fillWeight: 3 // thicker lines for hachure
});
rc.rectangle(220, 15, 80, 80, {
  fill: 'red',
  hachureAngle: 60, // angle of hachure,
  hachureGap: 8
});
rc.rectangle(120, 105, 80, 80, {
  fill: 'rgba(255,0,200,0.2)',
  fillStyle: 'solid' // solid fill
});

Fill styles can be: hachure(default), solid, zigzag, cross-hatch, dots, dashed, or zigzag-line

Rough.js fill examples

Sketching style

Rough.js rectangle

rc.rectangle(15, 15, 80, 80, { roughness: 0.5, fill: 'red' });
rc.rectangle(120, 15, 80, 80, { roughness: 2.8, fill: 'blue' });
rc.rectangle(220, 15, 80, 80, { bowing: 6, stroke: 'green', strokeWidth: 3 });

SVG Paths

Rough.js paths

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' });
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' });

SVG Path with simplification:

Rough.js texas map Rough.js texas map

Examples

Rough.js US map

View examples here

API & Documentation

Full Rough.js API

Credits

Some of the core algorithms were adapted from handy processing lib.

Algorithm to convert SVG arcs to Canvas described here was adapted from Mozilla codebase

Contributors

Financial Contributors

Become a financial contributor and help us sustain our community. [Contribute]

Individuals

Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

License

MIT License (c) Preet Shihn

rough's People

Contributors

43081j avatar bcjordan avatar briandouglasie avatar eddyvinck avatar mangtomas23 avatar noahsark769 avatar oreilles avatar pshihn avatar qwertyquerty avatar rodrigohahn avatar stof avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rough's Issues

Sync API by default?

Hello! Really great lib, thanks! I was wondering what's the motivation behind making draw API async by default? It makes it impossible to use synchronously, consider the following example

dykqvbzw4aaojiy

While it's trivial to lift sync API into async world, it's impossible to go the other way around. I imaging having async proxy would make it backwards compatible. Also I understand that it probably meant to run in a web worker, but since it's still can be executed on the main thread it would be nice to provide an "easier" way of consuming the API. Thanks!

Create SVG Renderer

Similar to RoughCanvas, RoughSVG will create an svg node

let rsvg = rough.svg(svgRoot, config);
let rect = rsvg.rectangle(10, 10, 100, 100);

// now can add custom styles to node
rect.classList.add('cool-rect');
svgRoot.appendChild(rect);

algorithms

Hi, great job!!! I'm very interested in the algorithm behind this, but a little hard to understand the code, will you give me some resource about the algorithm? thank you ^_^

Imported rough object doesn't exist when running tests in JSDom

I experienced an odd error when trying to test an app using this library. The app's written in Typescript, using React, using Jest and Enzyme for testing. I have a component that imports this library with
import rough from "roughjs";
then tries to use it to draw with this code:

const rc = rough.canvas(this.canvasRef.
rc.line(100, 0, 100, 300);

However, when running tests using react-scripts-ts --env=jsdom, this code error's out with Error: Uncaught [TypeError: Cannot read property 'canvas' of undefined. This happens even if canvas or canvas-prebuilt is installed in the project. I can fix the problem by checking if (rough) before drawing, which would seem to indicate that the rough object doesn't exist in the test environment.

Unrecognized segment command: e

roughGenerator.path will error out when given coordinates that are using scientific notation. Such as:

"M0,14.285714285714334L6.666666666666667,15.645165893991958L13.333333333333334,13.621434467236043L20,13.666889665817564L26.666666666666668,12.023412687602018L33.33333333333333,13.243774216451186L40,16.13238259981665L46.666666666666664,14.213536271906634L53.333333333333336,10.717681905478344L60,9.380249589210877L66.66666666666666,6.711179246747719L73.33333333333333,4.461618721950487L80,1.4708837451115357L86.66666666666667,3.359501689846894L93.33333333333333,0.03474343373119382L100,5.684341886080802e-14L106.66666666666667,2.603415833149171L113.33333333333333,6.052247452057372L120,9.12101436682056L126.66666666666666,9.141835233343272L133.33333333333331,9.0660892978415L140,9.953911817145155L146.66666666666666,12.450879362054053L153.33333333333334,9.649799726633688L160,13.035117833272778L166.66666666666669,9.896493775623355L173.33333333333334,11.033623453666053L180,9.70015386837514L186.66666666666666,8.748002714353476L193.33333333333334,10.960013271080328L200,12.351601607315104L200,21.645476831474497L193.33333333333334,18.538159084791687L186.66666666666666,19.765878642824674L180,18.524637635901854L173.33333333333334,23.13767925589468L166.66666666666669,20.0561877117795L160,23.922978272291886L153.33333333333334,21.327285732462798L146.66666666666666,22.835220857805837L140,19.464872113830666L133.33333333333331,21.48062185638247L126.66666666666666,24.949540935783574L120,22.804503808048736L113.33333333333333,22.62795094018361L106.66666666666667,16.31183693402673L100,13.068864406281222L93.33333333333333,12.896195068125735L86.66666666666667,15.41399692966391L80,16.000620863852532L73.33333333333333,18.38334497905032L66.66666666666666,19.79949753439365L60,19.95550516109813L53.333333333333336,22.212629025892227L46.666666666666664,24.86703498591848L40,29.122837164608313L33.33333333333333,23.293803174076174L26.666666666666668,21.881592853666803L20,20.690654271435704L13.333333333333334,19.552547736496933L6.666666666666667,20.740111759007306L0,21.428571428571473Z"

Issue appending svg element in js vs. using hardcoded svg element

Hey! This is possibly a noob question but here we go!

I want to use this library to create custom html markers on a map. The issue is that the markers are generated in javascript and not hardcoded. Basically, doing something like this doesn't work:

const el = document.createElement('svg');
el.id = 'svg';
document.getElementsByTagName("BODY")[0].appendChild(el);
const rc = rough.svg(el)
svg.appendChild(rc.circle(80, 120, 50, {roughness: 2.8, fill: 'black'}))
svg.appendChild(rc.line(80, 120, 300, 100, {roughness: 2.8, fill: 'black'}))

The code: https://jsfiddle.net/szvoqhhf/

Am I missing something? I see the g and path element being appended properly. Should I be using https://github.com/pshihn/rough/wiki/RoughGenerator#svg-path-info?

Return SVG path data

Would it be possible to add a feature that just returns SVG path data (just the d attribute of the fill and the d attribute of the stroke if any) instead of having rough append SVG nodes to the DOM. I'd find this easier to integrate into React that way.

Adding transform attribute to svg rendering

Thanks for this, really great resource.

Wanting to use for my physics svg files which make use of transform attribute:
<path d="M 0,0 A 11.25 9 0 0 0 11.25,-9 A 3.75 6 0 1 0 3.75,-9 A 11.25 9 0 0 0 15,0 A 11.25 9 0 0 0 26.25,-9 A 3.75 6 0 1 0 18.75,-9 A 11.25 9 0 0 0 30,0 A 11.25 9 0 0 0 41.25,-9 A 3.75 6 0 1 0 33.75,-9 A 11.25 9 0 0 0 45,0 A 11.25 9 0 0 0 56.25,-9 A 3.75 6 0 1 0 48.75,-9 A 11.25 9 0 0 0 60,0" transform="translate(100,90) rotate(153.435)"></path>
Is there functionality available to do the translation/rotations, etc?

Event Handling

How do I handle click/touch/drag events?
And make my object react according to these events?

Failed to minify rough.umd.js:19

I'm getting this error when trying to build Semiotic using roughjs 2.1.1:

Creating an optimized production build...
Failed to compile.

Failed to minify the code from this file: 

 	./node_modules/roughjs/dist/rough.umd.js:19 

Option to eliminate randomness

It would be great if there was an option to eliminate randomness when drawing shapes. So basically that the first time it would be random, and then the same shape would be drawn again.

For example drawing lines on canvas and then redrawing the entire canvas causes the lines to flicker due to randomness.
roughjs

I would be willing to work on this as a PR, if you think it's a good idea.

rectangle not working correctly

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

Line draws correctly but both rectangles draw with wrong co-ordinates

Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The canvas width is 0

Hi, I modify the demo with D3 version 4 success.
https://died.github.io/us-map.html

But when I change topojson to other country, it give out a error

Uncaught (in promise) DOMException: Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The canvas width is 0.
at t.path (https://cdn.jsdelivr.net/gh/pshihn/rough/dist/rough.min.js:1:24757)

I think it should be topojson content issue but it's my first time using topojson, so I have no idea to fix it, any tips ? Thank.

topojson source
https://github.com/jason2506/Taiwan.TopoJSON/blob/master/topojson/counties.json

code different with Taiwan topojson, other same as us-map.html

      d3.json("counties.json", async (error, tw) => {
        if (error) throw error;
        let topo = topojson.feature(tw, tw.objects.map).features;
        for (let feature of topo) {
          await rc.path(path(feature), {
            fill: randomColor(),
            fillStyle: randomStyle(),
            hachureAngle: randomAngle()
          });
        }
      });

option to not stroke?

Can prevent a polygon stroke by setting stroke: 'transparent'.
Maybe setting to null can avoid unnecessary paint calls?

`RoughSegmentRelation`

segment.js exports a function RoughSegmentRelation which merely returns an object:

export function RoughSegmentRelation() {
  return {
    LEFT: 0,
    RIGHT: 1,
    INTERSECTS: 2,
    AHEAD: 3,
    BEHIND: 4,
    SEPARATE: 5,
    UNDEFINED: 6
  };
}

In every single place the value is used outside of the segment.js file, the function is called and a particular key is accessed. For example, in renderer.js:

      if (s1.compare(s2) == RoughSegmentRelation().INTERSECTS) {

Questions:

  1. is the import in canvas.js necessary? It is not used in the body of canvas.js.

  2. hachure.js calls the function twice and accesses the same key:

        if (s.compare(this.sLeft) == RoughSegmentRelation().INTERSECTS) {
...
        if (s.compare(this.sRight) == RoughSegmentRelation().INTERSECTS) {

Shouldn't that value just be cached? Ideally the entire thing would be cached, in the same way that segment.js caches the value in RoughSegmentRelationConst

  1. every use of RoughSegmentRelation outside of segment.js follows the same pattern:
if(segment1.compare(segment2) == RoughSegmentRelation().INTERSECTS)

SEPARATE and UNDEFINED are theoretically interesting distinctions, but that is not used outside of the implementation of compare. Would it make more sense to convert that to an intersects method that just returned true if the two segments intersected?

Default Property Values Incorrect in Documentation

In the documentation, the default values for fillWeight, hachureGap, and simplification are incorrect.

fillWeight is listed as strokeWidth, but the default is -1
hachureGap is listed as strokeWidth, but the default is -1
simplification is listed as 1, but the default is 0

this.canvas.getContext is not a function

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #main {
            width: 800px;
            height: 600px;
            margin: 40px auto 0;
            padding: 16px;
            border: 1px solid #ddd;
        }
    </style>
</head>
<body>
<main id="myCanvas"></main>

<script src="../node_modules/roughjs/dist/rough.min.js"></script>
<script>
    window.onload = function () {
        rough.canvas(document.getElementById('myCanvas'));
    }
</script>
</body>
</html>

chrome version: 64.0.3282.186

rough.min.js:1 Uncaught TypeError: this.canvas.getContext is not a function
    at new t (rough.min.js:1)
    at Object.canvas (rough.min.js:1)
    at window.onload (index.html?_ijt=8kj4phaq3k33cqhrm3gobggm4f:25)

Allow for serverside rendering with jsdom

I'd like to use roughjs serverside with jsdom, but rough breaks when the global variable self isn't present. I saw that there are a couple of areas where self is used, surrounded by checks, but the checks themselves break because of a referenceerror.

I updated the checks to not throw an error when self doesn't exist in #68.

i made it to 8000 stars.

this tool looks beautiful i hope someone makes a chart.js using it so i can then use it.
also some sketch font would be cool otherwise the chart could look wierd.

fill overflow

rc.polygon([[0, 0], [44, 0], [216/2, 185-75], [216-44, 0], [216, 0], [216/2, 185], [0, 0]], { fill: '#41b883', stroke: '#41b883' })

Is this a bug or normal?

miscalculation of midDispY

Hi, very nice project! I love it !

I found a miscalculation at line 545 in renderer.js (also line 1190 in rough.js)

    let midDispX = o.bowing * o.maxRandomnessOffset * (y2 - y1) / 200;
    let midDispY = o.bowing * o.maxRandomnessOffset * (x1, x2) / 200;

I think It would be ...

    let midDispX = o.bowing * o.maxRandomnessOffset * (y2 - y1) / 200;
    let midDispY = o.bowing * o.maxRandomnessOffset * (x1 - x2) / 200;

Best regards

Parse an existing SVG?

As it already has Path support I imagine this would be more about actually finding the paths in an svg and passing them in one by one (including fill color).

Thoughts on practicality? Seems like it would be a useful feature. I know it would involve some kind of really gnarly regex...

Can I add text with roughjs?

Can I add text with roughjs?

It seems that there is no function I can use to draw text like drawing a rectangle.

And when I simply use codes like this:
"var ctx=canvas.getContext("2d");
ctx.fillText("Hello World",10,50);"
Nothing appears on the canvas.

Is there anyway that I can put text on the canvas while I'm using rough?

Hachure fill cutoff in SVG-Path polygons

I found out the hachure fill in SVG-Path shapes is limited to the size of the canvas.
This means a shape larger than the canvas itself will be not filled completely.

See my codepen for demonstration
(The startingpoint can be moved with the sliders, the other points are fixed to the edges. Moving the startingpoint to negative values results in the hachure fill being cut off at the bottom/right)

SVG options are not optional

Thanks for adding TypeScript typings!

I just created a circle and wanted to set the stroke but discovered that the options parameter requires almost all fields to be supplied. Is this expected behaviour?

This is the interface for SVG Options:

export interface Options {
  maxRandomnessOffset: number
  roughness: number
  bowing: number
  stroke: string
  strokeWidth: number
  curveTightness: number
  curveStepCount: number
  fill: string | null
  fillStyle: string
  fillWeight: number
  hachureAngle: number
  hachureGap: number
  simplification?: number
}

For some reason, only simplification is optional.

Add support for alternating hachure

I would love to see an option for a zig-zag hachure fill pattern like in the handy processing library with setIsAlternating(true).

I think it is a more realistic way of filling a shape when drawing quickly to zig-zag it instead of drawing countless paralell lines.

Incorrect rendering of SVG arcs

It's me again. ๐Ÿ˜

I tried creating shapes with the rc.path() function using SVG-Paths.
But the arcs which are supposed to appear are not drawn correctly using the rough-canvas.
I tried fiddling with the comma-separators between values, relative a and absolute A instructions, none of them creates the right shape.
Drawing the shape directly to the danvas via a Path2D object works fine.

Interestingly enough, the fill for the shape is rendered correctly, just the outline is rendered wrong.
Also the four examples found on the website work perfectly in the same canvas.

I created a codepen to illustrate the issue -> codepen

Am I missing something again or is this an actual bug?

TS compilation since Async feature

Hello @pshihn, thank you for this great contribution ๐Ÿ‘ฏ ๐Ÿ‘

Since version 2.2.0, which introduce async methods, I'm not being able to build the library inside angular 6 app.
I do not provide OS and versions information because the issue reside on types of RoughCanvasAsync (promise of...) not matching the implemented class RoughCanvas.

Here you could see an evidence Build Status

Add support for randomness-seed option

I tried to create a little drawing application.
For this I collect shapes in an array which is repainted to a canvas when something changes or something new is created.
But this results in already drawn shapes to be re-rendered with new randomness each time, which causes these shapes to flicker, even when they are not changing.
(since there is no way to delete a shape, I have to reset the canvas to white every render)

For cases like this there could be an option to pass along to the render-methods to supply a custom seed for randomness for the roughness. Then it would render identically each time.
e. g. roughCanvas.rectangle(10, 10, 200, 200, { randomSeed: 1234567 });

Visualzation of use case

Since Math.random() does not support seeding, a custom random number generator is needed.

If wanted, I'd happily implement this and supply a pull request if we can think of a suitable random number algorithm.

hachure vs hatching

Not a big issue but I think based on a google search alone
hachure is
parallel lines used in hill-shading on maps, their closeness indicating steepness of gradient.

hatching or cross hatching
(in drawing or graphics) shade (an area) with intersecting sets of parallel lines.

maybe hatching is better?

using in react?

How can I use this library in my react or react-native app?

Crashes when appending defs for a polygon or path

When using this library in node, rendering a polygon with a transparent fill fails with Cannot read property 'appendChild' of null. It originates on this line which was built from this line in svg.ts.

When it tries to run this.defs!.appendChild(pattern);, this.defs is null, so it fails. I'm not familiar with typescript, so I'm not sure what the exclamation mark is for , but skipping this assignment when this.defs === null fixes the error.

For reproduction, I'm attempting to rendering the following polygon:

// Coordinates
[ [ 50, 160 ],
  [ 55, 180 ],
  [ 70, 180 ],
  [ 60, 190 ],
  [ 65, 205 ],
  [ 50, 195 ],
  [ 35, 205 ],
  [ 40, 190 ],
  [ 30, 180 ],
  [ 45, 180 ] ]

// Options
{ stroke: 'green', fill: 'transparent', strokeWidth: 5 }

Circle, ellipse and rectangle do not have this issue, but path crashes with the same error. Let me know if you need more information.

Fill is sometimes outside the polygon

If I define a polygon like this, the "filling" ends up outside the polygon: https://jsfiddle.net/mtytutua/

    rc.polygon([
      [100, 100], [300, 100], [300, 200], [200, 200],
      [200, 300], [300, 300], [300, 400], [100, 400], [100, 100]], {
      stroke: 'red',
      hachureAngle: 65,
      fill: 'rgba(0,0,255,0.6)'
    });

It looks like part of the "filling" is doubled.

Great library BTW!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.