Create an SVG organic shape generator with D3.js

Posted on July 23, 2021 in
2 min read

There are tons of organic shape generators out there, some of them even charge money to download the shape.

I thought it might be nice to write a little tutorial on how to build your own generator with few lines of code.

Here the walk-through:

The SVG part

We use an SVG to hold the path we want to generate, thus, in the HTML let's put an SVG tag:

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
     viewBox="0 0 500 500"></svg>

I've included also the xmlns attributes in order to be able to download the SVG as valid file.

The JS (and D3.js) part

Let's follow along the lines the relevan parts:

Define some variables we can tweak in order to get different results:

let n = 5 // number of points
let f = 0.1 // level of randomness
let color = '#978af2' // fill color

Then, we prepare some D3.js specific helpers to make the calculation for us:

const mapX = d3.scaleLinear()
    .domain([-1, 1])
    .range([100, 400])

const mapY = d3.scaleLinear()
    .domain([-1, 1])
    .range([100, 400])

Now, time to create some elements in our document, with some D3.js methods:

const svg = d3.select('svg') // our container

const path = d3.line()
    .x(d => mapX(d.x))
    .y(d => mapY(d.y))
    .curve(d3.curveBasisClosed) // this smooth the path

const thePath = svg.append('path')

The final part is the draw function where all the magic happens on every run and where D3.js shines. We create a little dataset, a list of points using a bit of trigonometry.

const draw = () => {
  
  // this is the core part, we create a dataset of points
  const data = d3.range(n).map((d,i) => {
      const w = Math.PI * 2 / n
      const a = w * i 
      const x = Math.cos(a) + (Math.random()*f - (f/2))
      const y = Math.sin(a) + (Math.random()*f - (f/2))
      return {x, y}
  })
  
  // update the path
  thePath.transition()
    .attr('d', path(data))
    .style('fill', color)
}

The last chunk is just the function call:

draw()

You can see the same code in this Codepen or play with a enhanced version with some UI elements here.

PS: if you're going to create a service that generate an organic shape out of this tutorial, please credit it where is due :)