HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Drawing a color wheel... faster?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fasterwheelcolordrawing

Problem

Using the following code, I am able to neatly draw a color wheel, however, performance is barely acceptable on a high end machine. Now, I know some tricks I could employ to make it run far more smoothly, at the cost of a lot of flexibility, but I am especially interested in optimizing the code itself (thus keeping the flexibility). And of course in any generic feedback.



// Utility functions (ignore mostly)
function hsv2rgb(h, s, v) {
var c = v * s;
var h1 = h / 60;
var x = c * (1 - Math.abs((h1 % 2) - 1));
var m = v - c;
var rgb;

if (typeof h == 'undefined') rgb = [0, 0, 0];
else if (h1






I am asking for a code review, but if anybody knows what's causing the white lines (the Moiré pattern) appear at a low
value` (the slider) then I would be forever grateful. Or rather, I get why they appear, I just don't know how to solve it... beyond doubling the resolution and downscaling.

Solution

I like the idea of drawing it using arc segments, but it's probably not the most efficient. There's no doubt some extra loss in coverting to a CSS-style rgb(...) string, which then has to be parsed again. And, as you say, it causes the Moiré artefacts. Otherwise, the code looks pretty good.

While I won't guarantee it's always faster (and there are some browser support issues), you can try drawing the the color wheel pixel by pixel to an ImageData object, and pushing that to the canvas all at once. It seems faster, but I've also left out clipping the data to a wheel shape here.

You might also consider a square color field (rather than a wheel). That what this is of course, but the corners of it aren't too useful. Photoshop, for instance, defaults to a square field with saturation / lightness along the axes, and the slider determining the hue.

But Photoshop also has an RGB mode, where two of the components are used for the axes, and the last one is controlled by the slider. If you can construct a field that only requires you to update 1 byte per pixel, that'd probably be faster still.



var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var rangeEl = document.getElementById('range');

function drawPicker() {
// grab the current ImageData (or use createImageData)
var bitmap = context.getImageData(0, 0, 150, 150);

for (var y = 0; y






Alternative to that: Cheat! Make the CSS background of the canvas black, and fade the color wheel in front of it using the slider. That's one way to get away with just changing 1 byte per pixel, and letting the browser handle compositing.



var canvas = document.getElementById("picker");
var context = canvas.getContext("2d");
var rangeEl = document.getElementById('range');
var colorWheel = null;

// update the alpha bytes of the color wheel
function updatePicker() {
var bitmap = context.getImageData(0, 0, 150, 150);
for (var y = 0; y
#picker {
background: black
}







Or better yet: Cheat completely. Just put an image of a color wheel on top of a black box, and fade the image using the slider. No canvas, no pixel manipulation, none of that.



var wheel = document.getElementById("wheel"),
slider = document.getElementById("slider");

slider.addEventListener("change", function () {
wheel.style.opacity = this.value;
});

#picker {
width: 150px;
background: black;
}








That's probably the simplest :)

Note: I haven't benchmarked any of the above. That's left as an exercise to the reader.

Context

StackExchange Code Review Q#69887, answer score: 5

Revisions (0)

No revisions yet.