How do I calculate this color wheel?

Currently, I am using a color wheel and it is working fine (image below).

But I am trying to make it like the second image, using 2 separate image how do I do this calculation?

Current wheel system:

What I want:

1 Like

So you want to make a fancy color wheel. Good luck.
This very long wall of text occasionally uses <abbr> tags. Hover to read more.

The boring part

You’ll probably want to use these 2 images. 1024x1024, do whatever you want with them. I don’t care, despite having spent at least an hour of my life writing Lua code to generate them, and even more to type this very long reply.


This could be a static ImageLabel of any (square) size. No background.


This could be an ImageButton parented to the static ImageLabel. No background, 100% size. To achieve the effect I assume you want, you could change its ImageColor3 based on the selected hue, possibly using the Color3 HSV functions.


The fun part

To make this color wheel interactive, you’ll want to listen to mouse inputs. Suppose you have a function click(x: number, y: number). How that function is called is left as an exercise for the reader. It could be something with that ImageButton. Maybe some signals. UserInputService to handle edge cases of Roblox not firing signals.
The arguments x and y could be the relative position of the mouse, with -1, -1 being the top left corner of the image and 1, 1 being the bottom right corner. Given this relative position:

  • The inner square’s top left and bottom right corners are at -0.5, -0.5 and 0.5, 0.5 respectively.
    • For mouse events, you might want to use the entire inner circle, but clamp the values of x and y to -0.5…0.5.
    • H is the selected hue.
    • S depends on x and can be calculated using x + 0.5. Left is no saturation, right is full saturation.
    • V depends on y and can be calculated using -y + 0.5. Bottom is black.
  • The outer ring starts at a radius of 0.8 and ends at 1, leaving the corners of the image transparent.
Do you like trigonometry? Read this if you don't know how to get the hue.

Hell

Enter math.atan2(y: number, x: number): number. It’s almost like magic (and even I don’t fully understand it).

How many lines of code do we need to find the selected hue based on the mouse position?
-- see "The fun part" for definition of x and y
-- conversion to degrees could be skipped, but it doesn't really matter
-- as long as you get a number from 0 to 1
local hue = math.deg(math.atan2(y, x) + math.pi / 2) % 360 / 360
-- assuming btn is the ImageButton previously defined in "The boring part"
btn.ImageColor3 = Color3.fromHSV(hue, 1, 1)

One. 2 if you count the assignment of ImageColor3. More if you also count comments.


All of this information may or may not be useful for solving your problem. If it was, that’s great! If not, please ask as many questions as you can. I’ll do my best to attempt to answer them as soon as I return from being dead

18 Likes

Thank you so much for the in-depth explanation! I will put this into action.

2 Likes

Do I stack the images? That means I would have two of theses on top of each other right?

1 Like

Assuming the second image is parented to the first with the size defined in my first reply, it should look like this (second image ImageColor3 = Color3.new(1, 0, 0)):

2 Likes

Hey, I need some help with the color wheel, I can’t seem to get anything working with accurate values, it might be with the way I calculate the mouse position? Any suggestions?

1 Like

How do you calculate the mouse position?

2 Likes

I am checking to see if they are hovering over the label or whatever it is, then in input service mouse movement to then move the picker icon to the mouse, if the is in label == true, then do input.Position.Y, input.Position.Y

1 Like

That information doesn’t really explain anything. Could you post your code instead?

2 Likes

My get color function:

local colourPickerCentre = Vector2.new(ColorWheel.Picker.AbsolutePosition.X + (ColorWheel.Picker.AbsoluteSize.X/2),ColorWheel.Picker.AbsolutePosition.Y + (ColorWheel.Picker.AbsoluteSize.Y/2))
	local h = (math.pi - math.atan2(colourPickerCentre.Y - centreOfWheel.Y, colourPickerCentre.X - centreOfWheel.X)) / (math.pi * 2)

	local s = (centreOfWheel - colourPickerCentre).Magnitude / (ColorWheel.AbsoluteSize.X/2)

	local v = math.abs((mouseY - HueWheel.AbsolutePosition.Y) / HueWheel.AbsoluteSize.Y - 1)


	local hsv = Color3.fromHSV(math.clamp(h, 0, 1), math.clamp(s, 0, 1), math.clamp(v, 0, 1))

How I get centre of wheel:


centreOfWheel = Vector2.new(ColorWheel.AbsolutePosition.X + (ColorWheel.AbsoluteSize.X/2), ColorWheel.AbsolutePosition.Y + (ColorWheel.AbsoluteSize.Y/2))
selectedColor = getColor(centreOfWheel)

This is in a input changed, first makes sure that the inFrame is equal to true, which is set by a mouse.enter and mouse.leave, it checks for mouse down and mouse movement to where to move the color picker icon to

1 Like
	local h = (math.pi - math.atan2(colourPickerCentre.Y - centreOfWheel.Y, colourPickerCentre.X - centreOfWheel.X)) / (math.pi * 2)

Assuming one of an unknown number of issues with your code is the hue calculation, one way to (hopefully) fix that would be the following:

    local h = (math.atan2(colourPickerCentre.Y - centreOfWheel.Y, colourPickerCentre.X - centreOfWheel.X) + math.pi / 2) / (math.pi * 2) % 1

Could you upload a video of your color wheel misbehaving?

It took a concerning amount of effort to fix the hue issue. Most of that effort went into a complete recreation of the color wheel. This recreation made debugging (without the full code) a lot easier at the cost of potentially making all of your effort absolutely pointless.
colorwheel.rbxl (32.5 KB)
My sleep-deprived brain decided to turn the color wheel into a standalone UI component because apparently writing code for 2 hours is better than sleep.
yes

  • ColorWheel is an ImageLabel with the first image. It can be anywhere, with any size (for obvious reasons, it should be a square),[clarification needed] and any AnchorPoint. The attached place file is just an example.
  • WheelMain handles mouse input and ColorWheel's Color attribute (ColorWheel:GetAttribute("Color") and ColorWheel:SetAttribute("Color", Color3.new(1, 1, 1))).
  • H and SV are Frames indicating the current selection.
  • Button is an ImageButton with the second image and a dynamic ImageColor3.

Whenever the user clicks the color wheel, WheelMain starts handling mouse movement. The initial click determines which part of the color wheel should change whenever the mouse moves. This allows the user to click either the square or the hue wheel and drag anywhere, even outside the color wheel, potentially improving the user experience.[citation needed] The update function calculates the relative mouse position inside the frame based on the InputObject's Position and Button's AbsolutePosition and AbsoluteSize.

The part you probably care about because there must be something trying to get the color

External code can use ColorWheel's Color attribute to get (and set!) the color wheel’s selected color. ColorWheel:GetAttributeChangedSignal("Color") is a signal fired whenever the selected color changes. See attached place file for a simple demo; code in StarterGui.ScreenGui.demo.

End of the part you probably care about because there must be something trying to get the color

Because this is just a prototype, some of the code might be a bit messy. For example,

	if if lock then m < 0.8 else not huewheel then

I am not sorry. That if statement would be even worse without that if expression.

You shouldn’t feel bad about this. You tried your best, and you hopefully gained more scripting experience!

don’t expect a reply for at least 10 hours because that’s how much sleep I need thanks to this surprise time sink

8 Likes

Holy moly. You absolute legend, I can’t thank you enough, you really didn’t have to do all that, thank you so much have a great day and night

1 Like