Create a Color Wheel in Javascript with d3

Updated Feb 12, 2018

d3 is a well-known library for creating charts in Javascript but is also a great tool for drawing in general. In this post we take advantage of d3’s arc, color, and interpolateRainbow modules to create a simple color wheel. The “Scramble” and “Restore” buttons are included for fun to show how dead simple animations are with d3:

To get started, import dependencies and create the main SVG element:

Getting started Copy
import {
  arc                as d3_arc,
  color              as d3_color,
  interpolateRainbow as d3_interpolateRainbow,
  range              as d3_range,
  select             as d3_select
from 'd3';
const SIZE         = 400;
const SIZE_INNER   = 70;
const BANDS        = 6;
const BAND_WIDTH   = (SIZE - SIZE_INNER) / BANDS;
const MIN_OPACITY  = 0.1;
const OPACITY_STEP = (1 - MIN_OPACITY) / BANDS;
const COUNT        = 12;
const COLORS       = d3_range(COUNT).map( (d, i) => d3_interpolateRainbow(i/COUNT) );
const svg = d3_select('#color-wheel').append('svg')
  .attr('width', SIZE)
  .attr('height', SIZE)
  .append('g')
    .attr('transform''translate(' + (SIZE/2+ ',' + (SIZE/2+ ')');

Next create the wheel. We first create a g element for each band, then create a series of path elements on each band, bound to the COLORS data:

Create the wheel Copy
for (let k = 0; k < BANDS; k++) {
  const arc = d3_arc()
    .outerRadius((SIZE - k*BAND_WIDTH) / 2)
    .innerRadius((SIZE - (k+1)*BAND_WIDTH) / 2)
    .startAngle(0)
    .endAngle((2*Math.PI/ COUNT);
  svg.append('g')
    .attr('class''band')
    .selectAll('path').data(COLORS)
    .enter()
    .append('path')
      .attr('fill', d => {
        const c = d3_color(d);
        c.opacity = (1 - OPACITY_STEP * k);
        return c + '';
      })
      .attr('stroke''#fff')
      .attr('stroke-width'2)
      .attr('transform', (d, i) => 'rotate(' + (i*(360/COUNT)) + ')')
      .attr('d'arc());
}

At this point you should have a color wheel that looks like the example at top. The “Scramble” and “Restore” buttons have click handlers that simply change the rotation of each band:

Create the buttons Copy
d3_select('#buttons').append('button')
  .text('Scramble')
  .on('click', () => {
    svg.selectAll('.band')
      .transition().duration(1000)
      .attr('transform', () =>
        'rotate(' + (360/COUNT)*Math.floor(COUNT * Math.random()) + ')'
      );
  });
d3_select('#buttons').append('button')
  .text('Restore')
  .on('click', () => {
    svg.selectAll('.band')
      .transition().duration(1000)
      .attr('transform''rotate(0)');
  });

The above assumes we have a #buttons container element in the DOM where we attach the buttons. The “Scramble” button rotates each band to a random degree aligned with the existing colors. The “Restore” button simply returns the rotation to 0.

Comments

No comments exist. Be the first!

Leave a comment