I am trying to draw a color wheel for an iPhone, but I can't get the gradient to rotate around a point. I am trying to use gradients but objective-c provides a linear gradient, which draws a gradient in a straight line like this:
and a radial gradient, which draws the gradient starting at point and radiating out in all directions like this:
I want to draw a linear gradient that rotates around a point like this:
Draw the outer circle 8 1⁄2 inches (22 cm) from the center. Move the leg of your drawing compass so it extends 8 1⁄2 inches (22 cm) from the middle of the color wheel and draw the largest circle. [5] This will be the border for your color wheel. You should now have 3 rings for the color wheel that you'll divide into spaces.
Draw the outer circle 8 1⁄2 inches (22 cm) from the center. Move the leg of your drawing compass so it extends 8 1⁄2 inches (22 cm) from the middle of the color wheel and draw the largest circle. This will be the border for your color wheel. You should now have 3 rings for the color wheel that you'll divide into spaces.
Lay a ruler horizontally on the center of the square and make a small mark in the middle using a pencil. Then, turn the ruler vertically so it's lined up with your mark and make a small dot in the center. [2] The small dot will be the center of your color wheel. Use a compass to make a small circle 2 1⁄2 inches (6.4 cm) away from the center.
Variation: To make a simple 12-color color wheel, just draw the large outer circle for the color wheel and don't make the smaller circles within it. Make another circle that's 5 1⁄2 inches (14 cm) from the center dot. To create another row for your color wheel, make a slightly larger circle beyond the small one you just made.
The following draws an HSL color wheel in a UIView subclass. It does this by generating a bitmap by computing, for each pixel, the correct color value. This is not exactly what you're trying to do (looks like it's just hue varies in the circle with a constant luminance/saturation), but you should be able to adapt it for your needs.
Note that this may not have optimal performance, but it should get you started. Also, you can use getColorWheelValue()
to handle user input (clicks/touches at a given coordinate).
- (void)drawRect:(CGRect)rect { int dim = self.bounds.size.width; // should always be square. bitmapData = CFDataCreateMutable(NULL, 0); CFDataSetLength(bitmapData, dim * dim * 4); generateColorWheelBitmap(CFDataGetMutableBytePtr(bitmapData), dim, luminance); UIImage *image = createUIImageWithRGBAData(bitmapData, self.bounds.size.width, self.bounds.size.height); CFRelease(bitmapData); [image drawAtPoint:CGPointZero]; [image release]; } void generateColorWheelBitmap(UInt8 *bitmap, int widthHeight, float l) { // I think maybe you can do 1/3 of the pie, then do something smart to generate the other two parts, but for now we'll brute force it. for (int y = 0; y < widthHeight; y++) { for (int x = 0; x < widthHeight; x++) { float h, s, r, g, b, a; getColorWheelValue(widthHeight, x, y, &h, &s); if (s < 1.0) { // Antialias the edge of the circle. if (s > 0.99) a = (1.0 - s) * 100; else a = 1.0; HSL2RGB(h, s, l, &r, &g, &b); } else { r = g = b = a = 0.0f; } int i = 4 * (x + y * widthHeight); bitmap[i] = r * 0xff; bitmap[i+1] = g * 0xff; bitmap[i+2] = b * 0xff; bitmap[i+3] = a * 0xff; } } } void getColorWheelValue(int widthHeight, int x, int y, float *outH, float *outS) { int c = widthHeight / 2; float dx = (float)(x - c) / c; float dy = (float)(y - c) / c; float d = sqrtf((float)(dx*dx + dy*dy)); *outS = d; *outH = acosf((float)dx / d) / M_PI / 2.0f; if (dy < 0) *outH = 1.0 - *outH; } UIImage *createUIImageWithRGBAData(CFDataRef data, int width, int height) { CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGImageRef imageRef = CGImageCreate(width, height, 8, 32, width * 4, colorSpace, kCGImageAlphaLast, dataProvider, NULL, 0, kCGRenderingIntentDefault); UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; CGDataProviderRelease(dataProvider); CGColorSpaceRelease(colorSpace); CGImageRelease(imageRef); return image; } // Adapted from Apple sample code. See http://en.wikipedia.org/wiki/HSV_color_space#Comparison_of_HSL_and_HSV void HSL2RGB(float h, float s, float l, float* outR, float* outG, float* outB) { float temp1, temp2; float temp[3]; int i; // Check for saturation. If there isn't any just return the luminance value for each, which results in gray. if(s == 0.0) { *outR = l; *outG = l; *outB = l; return; } // Test for luminance and compute temporary values based on luminance and saturation if(l < 0.5) temp2 = l * (1.0 + s); else temp2 = l + s - l * s; temp1 = 2.0 * l - temp2; // Compute intermediate values based on hue temp[0] = h + 1.0 / 3.0; temp[1] = h; temp[2] = h - 1.0 / 3.0; for(i = 0; i < 3; ++i) { // Adjust the range if(temp[i] < 0.0) temp[i] += 1.0; if(temp[i] > 1.0) temp[i] -= 1.0; if(6.0 * temp[i] < 1.0) temp[i] = temp1 + (temp2 - temp1) * 6.0 * temp[i]; else { if(2.0 * temp[i] < 1.0) temp[i] = temp2; else { if(3.0 * temp[i] < 2.0) temp[i] = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - temp[i]) * 6.0; else temp[i] = temp1; } } } // Assign temporary values to R, G, B *outR = temp[0]; *outG = temp[1]; *outB = temp[2]; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With