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:
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:
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:
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
Leave a comment