I'm playing with HSV color. I have an array of hsv after convert from rgb color:
//hsv[0], hsv[1], hsv[2]
var hsv = rgbToHsv(rgb[0], rgb[1], rgb[2]);
I will add or subtract it
hsv[0] += ...
hsv[1] += ...
hsv[2] += ...
And I need to valid the value before convert it back to rgb. What is the valid range of hsv?
Here is the function I using to convert rgb to hsv
function rgbToHsv(r, g, b) {
var r = (r / 255),
g = (g / 255),
b = (b / 255);
var min = Math.min(Math.min(r, g), b),
max = Math.max(Math.max(r, g), b),
delta = max - min;
var value = max,
saturation,
hue;
// Hue
if (max == min) {
hue = 0;
} else if (max == r) {
hue = (60 * ((g-b) / (max-min))) % 360;
} else if (max == g) {
hue = 60 * ((b-r) / (max-min)) + 120;
} else if (max == b) {
hue = 60 * ((r-g) / (max-min)) + 240;
}
if (hue < 0) {
hue += 360;
}
// Saturation
if (max == 0) {
saturation = 0;
} else {
saturation = 1 - (min/max);
}
return [(hue), (saturation * 100), (value * 100)];
}
Roughly the same algorithm is used for this online converter. You can check the article after for the opposite conversion.
H is definitely between 0 and 360, but regarding S and V it is different. Like most values for color conversion or color blending mode calculation, a float between 0 and 1 is used. I would say it is better because beeing a float means you can have all the levels of precision you want.
Now it is not uncommon (like on this online converter and your current javascript) to multiply it by 100 to get a percentage. Often rounded as well. What is important to understand with this rounding is that obviously it increases the chances of you getting a different RGB color if you convert back and forth rgb > hsv > rgb. If this is important, then you're better with the floats.
Since you are asking what is "valid", I would say it only depends on how you want to use it or where these numbers will be used.
Related
I'm making a color game via a course which generates 6 squares with random colours. When you click on a square which corresponds with the target color, you win the game.
Here's a link to how the game should work using RGB:
https://jsfiddle.net/jdwrgbh0/
I'm using HSL values instead.
Here's my code using HSL:
https://jsfiddle.net/fh7boykd/
(The only difference is this code for generate random colors)
function randomColor() {
var h = Math.floor(Math.random() * 361);
var s = Math.floor(Math.random() * 101);
var l = Math.floor(Math.random() * 101);
return "hsl(" + h + ', ' + s + '%' + ', ' + l + '%' + ")";
}
Even though I used the function above to generate HSL values, the background-color of the squares still shows RGB values instead of HSL values and as such, I can't win the game because the target color is never shown. I want the color of the squares to display background-color in HSL and not RGB. The above randomColor function seems fine and testing it in the console, it does seem to generate a random color after it's invoked each time.
Here's an image of the console when I run the code. The background-color is in RGB and not HSL.
I think the problem may be related to this function:
function changeColors(color){
//loop through all squares
for(var i = 0; i < squares.length; i++){
//change each color to match given color
squares[i].style.background = color;
}
}
This code changes the color of each square. When I look at the browser console, it shows RGB values instead of HSL values. How do I force squares[i].style.background = color; to use HSL instead of RGB?
The browser will convert your HSL back to RGB colors. From what I see in your question, you are using HSL just so you can generate random colors. You can also use this piece of code to generate random hex color code
var generateRandomHexColor = () => {
var allPossibleLetters = '0123456789ABCDEF';
var HexCode = '';
for (var i = 0; i < 6; i++) {
HexCode += allPossibleLetters[Math.floor(Math.random() * 16)];
}
return '#' + HexCode;
}
console.log(generateRandomHexColor())
I believe your question is that you want to be able to convert RGB to HSL and then understand that HSL value. This is entirely possible. I have found some js script off of github, from user mjackson.
/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* #param Number r The red color value
* #param Number g The green color value
* #param Number b The blue color value
* #return Array The HSL representation
*/
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [ h, s, l ];
}
You may be able to adapt this to the way that you wish. I hope this helped.
Cheers!
if you want to set as hsl, just like this format:
divElement.style.backgroundColor = "hsl(155,100%,30%)";
but you want to got the style, that must be rgb or rgba string. so you must change it to hsl by your self.
I want to change color of the dot every time it hits the wall. I saw few solutions, but I don't know why mine isn't working.
Here's the part responsible for changing color:
function chColor() {
hex = Math.floor(Math.random() * 100000 + 1);
color = '"' + "#" + hex + '"';
color.toString();
return color;
}
And here is not working fiddle:
https://jsfiddle.net/vpzd7ye6/
Colour overkill
This answer is way overkill and I was about to discard it, but, why not give a Better random colour for those who may need it... (|:D
When random seams less random
Selecting a random totally random colour for us humans does not work that well if you wish to have a clear distinct change that attracts the eye from one colour to the next.
The problem is that many of the colour values available are very close to white or black and a totally random colour may be very close to the last making the change impossible to notice.
Simple random colour
So first the simple random colour picks a totally random colour from all of the 16,777,216 possible colours.
function randColor(){
return "#" +
(Math.floor(Math.random() * 0x1000000) + 0x1000000)
.toString(16)
.substr(1);
}
The function works by finding a random 24 bit number (0 - 0xFFFFFF same as 0 - 16777216). Because numbers do not have leading zeros added all random values below 0x100000 will, when converted to hex have less than 6 digit (the CSS colour value requires 3 or 6 digit Hex value) so I add 0x1000000 to ensure that the number is > 0x100000 and will always have 7 digits. As the first (left most) digit is not needed I use substr to remove it. Then added the "#" and return.
The function Number.toString(radix) takes an argument called radix which specifies the base the number is converted to. It defaults if not supplied to 10 (base ten is what we humans use). The hex colour is base 16 so that must be specified. The toString radix argument can be any value from 2 (binary) to 36 (which uses characters 0-9 then A-Z)
Less is more Random
Ironically we humans tend to find less random sequences more random than true random sequences. Many music players use this type of random sequence when they have the play set to shuffle, to ensure tracks are not played twice in a row or that repeated sequences of tracks are played by random chance.
To make the random colour seem more random and distinct you should track the last colour return so that you can ensure you are not close to that colour. You should also use a random colour that stays away from the whites and blacks.
var randColour = (function(){ // as singleton so closure can track last colour
var lastHue = 0;
const minChange = 360 / 3; // Hue distance from last random colour
var lastVal = false; // for low high saturation and luminance
const randomAmount = 360 / 3; // random hue range
const minVal = 20; // how far from full black white to stay (percent)
const minSat = 80; // how far from grey to stay (percent)
return function(){
var hueChange = Math.random() * randomAmount ;
hueChange *= Math.random() < 0.5 ? -1 : 1; // randomly move forward or backward
lastHue += 360 + hueChange + minChange; // move away from last colour
lastHue %= 360; // ensure colour is in valid range
var sat = (Math.random() * (100 - minSat)) + minSat; // get saturation (amount of colour)
var val = (Math.random() * (50 - minVal * 2)) * 1.5; // get value (luminance)
// switch between high and low and luminance
lastVal = ! lastVal;
if(lastVal){
val = minVal + val;
} else {
val = 100 - minVal - val;
}
return "hsl(" + lastHue.toFixed(0) + "," + sat.toFixed(0) + "%," + val.toFixed(0) + "%)";
}
})(); // call singleton
This function returns a random colour but ensures that the saturation and value stay within a specific range and that the hue is at least 1/3 around the colour wheel from the last value. It cycles between low and low and high luminance values to make the colour change as clear as possible. Closure is used to keep track of the last colour returned. The function returns the random colour as a CSS hsl(hue, saturation, luminance) color string.
There are two constants that control the colour sequence. minVal set to 20 is the percentage to stay away from full black or full white. Valid range is 0-~50 and minSat set to 80 is how far to stay away from grays in percent.
const minSat = 80; // how far from grey to stay (percent)
Compare change
To compare the two methods the following demo shows side by side a set of random colours using both methods, then flashes a new random colour 4 times a second. The simple random colour will appear from time to time to miss a change. I leave it up to you to pick which side is which.
var canvas = document.createElement("canvas");
canvas.width = 620;
canvas.height = 200;
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
var randColour = (function(){ // as singleton so closure can track last colour
var lastHue = 0;
const minChange = 360 / 3; // min hue change
var lastVal = false; // for low high saturation and luminance
const randomAmount = 360 / 3; // amount of randomness
const minVal = 20; // how far from full black white to stay (percent)
const minSat = 80; // how far from grey to stay (percent)
return function(){
var hueChange = Math.random() * randomAmount ;
hueChange *= Math.random() < 0.5 ? -1 : 1; // randomly move forward or backward
lastHue += 360 + hueChange + minChange; // move away from last colour
lastHue %= 360; // ensure colour is in valid range
var sat = (Math.random() * (100 - minSat)) + minSat; // get saturation (amount of colour)
var val = (Math.random() * (50 - minVal * 2)) * 1.5; // get value (luminance)
// switch between high and low and luminance
lastVal = ! lastVal;
if(lastVal){
val = minVal + val;
} else {
val = 100 - minVal - val;
}
return "hsl(" + lastHue.toFixed(0) + "," + sat.toFixed(0) + "%," + val.toFixed(0) + "%)";
}
})(); // call singleton
function randColor(){
return "#" +
(Math.floor(Math.random() * 0x1000000) + 0x1000000)
.toString(16)
.substr(1);
}
const grid = 16;
var gridX = 0;
var gridY = 0;
var bigSize = grid - (grid / 3 ) * 2;
const xStep = Math.floor((canvas.width - 12) / (grid * 2));
const yStep = Math.floor(canvas.height / grid);
var count = 0;
function drawRandomColour(){
ctx.fillStyle = randColor(); // simple random colour
ctx.fillRect(gridX * xStep, gridY * yStep, xStep, yStep);
ctx.fillStyle = randColour(); // smart random colour
ctx.fillRect(gridX * xStep + canvas.width / 2, gridY * yStep, xStep, yStep);
if(count < grid * grid - 1){ // fill the grid
gridX += 1; // move to next grid
if(gridX > grid-1){
gridX = 0;
gridY += 1;
gridY %= grid;
}
count += 1;
setTimeout(drawRandomColour,1); // quickly fill grid
return; // done for now
}
// if grid is full pick a random grid loc and request the next random colour
gridY = gridX = (grid / 3);
setTimeout(centerChange,250); // every quarter second
}
function centerChange(){
ctx.fillStyle = randColor(); // simple random colour
ctx.fillRect(gridX * xStep, gridY * yStep, xStep * bigSize, yStep * bigSize);
ctx.fillStyle = randColour(); // smart random colour
ctx.fillRect(gridX * xStep + canvas.width / 2, gridY * yStep, xStep * bigSize, yStep * bigSize);
setTimeout(centerChange,250); // every quarter second
}
drawRandomColour(); // start it up.
Compare sequences
This demo just draws the random colours as a sequence of random values. Examine the sequences to see how often you see two or more colours in a row that are hard to distinguish between. You will find that the sequence on the left has more similar sequences than the one on the right.
Expand demo to full-page view to see both sequences.
Click to redraw sequences.
var canvas = document.createElement("canvas");
canvas.width = 1240;
canvas.height = 800;
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
var randColour = (function(){ // as singleton so closure can track last colour
var lastHue = 0;
const minChange = 360 / 3; // min hue change
var lastVal = false; // for low high saturation and luminance
const randomAmount = 360 / 3; // amount of randomness
const minVal = 20; // how far from full black white to stay (percent)
const minSat = 80; // how far from grey to stay (percent)
return function(){
var hueChange = Math.random() * randomAmount ;
hueChange *= Math.random() < 0.5 ? -1 : 1; // randomly move forward or backward
lastHue += 360 + hueChange + minChange; // move away from last colour
lastHue %= 360; // ensure colour is in valid range
var sat = (Math.random() * (100 - minSat)) + minSat; // get saturation (amount of colour)
var val = (Math.random() * (50 - minVal * 2)) * 1.5; // get value (luminance)
// switch between high and low and luminance
lastVal = ! lastVal;
if(lastVal){
val = minVal + val;
} else {
val = 100 - minVal - val;
}
return "hsl(" + lastHue.toFixed(0) + "," + sat.toFixed(0) + "%," + val.toFixed(0) + "%)";
}
})(); // call singleton
function randColor(){
return "#" +
(Math.floor(Math.random() * 0x1000000) + 0x1000000)
.toString(16)
.substr(1);
}
const grid = 32;
var gridX = 0;
var gridY = 0;
const xStep = Math.floor((canvas.width - 12) / (grid * 2));
const yStep = Math.floor(canvas.height / grid);
var count = 0;
function drawRandomColour(){
ctx.fillStyle = randColor(); // simple random colour
ctx.fillRect(gridX * xStep, gridY * yStep, xStep, yStep);
ctx.fillStyle = randColour(); // smart random colour
ctx.fillRect(gridX * xStep + canvas.width / 2, gridY * yStep, xStep, yStep);
if(count < grid * grid - 1){ // fill the grid
gridX += 1; // move to next grid
if(gridX > grid-1){
gridX = 0;
gridY += 1;
gridY %= grid;
}
count += 1;
setTimeout(drawRandomColour,1); // quickly fill grid
return; // done for now
}
}
drawRandomColour(); // start it up.
// redraw on click
canvas.addEventListener("click",function(){
if(count >= grid * grid - 1){
gridX = gridY = count = 0;
drawRandomColour();
}else {
gridX = gridY = count = 0;
}
});
Summary
Though the second random function is not perfect, It can from time to time get colours that within a context appear similar this occurs much less than by pure random. When it is important for the user to notice a visual changes the best approch is to cycle two complementary colours (hue + 180) with one having a high luminance and the other a low. The CSS hsl colour string makes it easy to pick luminance and hue and when you want random colours gives you better control.
The problem is in converting number to hex color string.
So you can write a function that converts random number to valid hex color (see what this function does):
function convertToColor(num){
return '#' + ('00000' + (num | 0).toString(16)).substr(-6);
}
and then just use it in chColor function:
function chColor() {
number = Math.floor(Math.random() * 100000 + 1);
color = convertToColor(number);
return color;
}
Here is the link with working example: jsfiddle
Also it makes sense to rename function to getRandomColor:
function getRandomColor(){
number = Math.floor(Math.random() * 100000 + 1);
return convertToColor(number);
}
Please check updated fiddle
I just changed your chColor function on this:
function chColor() {
color = "#" + ((1 << 24) * Math.random() | 0).toString(16);
return color;
}
I have updated the fiddle. Link https://jsfiddle.net/vpzd7ye6/2/
I made the following change to your change color function;
function chColor() {
hex = Math.floor(Math.random() * 1000000) + 1;
color = '' + '#' + hex + '';
return color;
}
I know how to generate a random number between two numbers. But what I'd like to achieve is a way to generate a number between two numbers in a not totally random way. Let me explain...
So I have a function that generates a color based on a number passed into it. If that number is between 0 and 600, I'd like it to pass a number between 0 and 120 to the hue of the hsl value. If the number is greater than 600, I'd like a number between 120 and 240 passed to the hue of the hsl value. My function looks something like this:
getColor:function (number {
var hue;
var color;
if (number <= 600) {
hue = [A number between 0 and 120];
} else if (number >= 600) {
hue = [A number between 120 and 240];
}
color = 'hsl(' + hue + ', 100%, 80%)'
return color;
}
So the higher the number passed into the function, for example, between 0 and 600, the higher the hue value between 0 and 120. That make sense?
Thx u
-- Gaweyne
Simple Math:
hue = Math.floor(number * 120 / 600);
Or with both points:
function transpose(smin, smax, dmin, dmax) {
var slen = smax - smin;
var dlen = dmax - dmin;
var ratio = dlen / slen;
return function(num) {
return num * ratio + smin;
}
}
transpose(0, 600, 0, 120)(300); // 60
Ok first of all you should know the maximum and minimum values of number. In my example The maximum value of number will be 1200 and the minimum 0, so the range is between 0 and 1200. And the range of hue is between 0 and 240.
the higher the number passed into the function, the higher the hue value.
0 hue = 0 number;
120 hue = 600 number;
240 hue = 1200 number;
=> 1 hue = (600 / 120) number = (1200 / 240) number
=> 1 hue = 5 number
In my example, (with number between 0 and 1200 and 600 is the middle) 1 value in hue is equal to 5 value in number. So :
hue = number / 5;
if you want hue to be an integer just use Math :
hue = Math.floor(number / 5);
In my example hue will grow up by 1 every time you add 5 to number, it doesn't matter if number is less or more than 600 because the range of number on both sides of 600 is the same (600 is in the middle of the range). In case this is not what you want, and 600 is not in the middle of the range, you will have to do the same calculation above twice.
var max = [maximum value of number];
var min = [minimum value of number];
getColor:function (number {
var hue;
var color;
if (number <= 600) {
hue = Math.floor( number / ((600 - min) / 120) );
} else if (number >= 600) {
hue = Math.floor( number / ((max - 600) / 120) ) + 120;
}
color = 'hsl(' + hue + ', 100%, 80%)';
return color;
}
I found on stackoverflow this color generator :
Math.random()*0xFFFFFF<<0
It works fine. The only problem is that I'd like to generate random colors, but only of different shades of grey.
I have no idea how I could achieve something like this.
var value = Math.random() * 0xFF | 0;
var grayscale = (value << 16) | (value << 8) | value;
var color = '#' + grayscale.toString(16);
color will be a random grayscale hex color value, appropriate for using in eg element.style properties.
Note: there are several ways to coerce the random floating-point number to an integer. Bitwise OR (x | 0) will usually be the fastest, as far as I know; the floor function (Math.floor(x)) is approximately the same speed, but only truncates for positive numbers (you'd have to use Math.ceil(x) for negative numbers). Bitwise operators won't work as expected for numbers that require more than 32 bits to represent, but Math.random() * 0xFF will always be in the range [0,255).
If you want to use RGB, rgb grays can be created by supplying the same number in all three arguments i.e. rgb(255,255,255) (the number must be between 0 and 255).
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
var randomNumberString = String(getRandomInt(0,255));
var color = "rgb(" + randomNumberString + "," + randomNumberString + "," + randomNumberString + ")";
I'm trying to interpolate between two colours in HSV colour space to produce a smooth colour gradient.
I'm using a linear interpolation, eg:
h = (1 - p) * h1 + p * h2
s = (1 - p) * s1 + p * s2
v = (1 - p) * v1 + p * v2
(where p is the percentage, and h1, h2, s1, s2, v1, v2 are the hue, saturation and value components of the two colours)
This produces a good result for s and v but not for h. As the hue component is an angle, the calculation needs to work out the shortest distance between h1 and h2 and then do the interpolation in the right direction (either clockwise or anti-clockwise).
What formula or algorithm should I use?
EDIT: By following Jack's suggestions I modified my JavaScript gradient function and it works well. For anyone interested, here's what I ended up with:
// create gradient from yellow to red to black with 100 steps
var gradient = hsbGradient(100, [{h:0.14, s:0.5, b:1}, {h:0, s:1, b:1}, {h:0, s:1, b:0}]);
function hsbGradient(steps, colours) {
var parts = colours.length - 1;
var gradient = new Array(steps);
var gradientIndex = 0;
var partSteps = Math.floor(steps / parts);
var remainder = steps - (partSteps * parts);
for (var col = 0; col < parts; col++) {
// get colours
var c1 = colours[col],
c2 = colours[col + 1];
// determine clockwise and counter-clockwise distance between hues
var distCCW = (c1.h >= c2.h) ? c1.h - c2.h : 1 + c1.h - c2.h;
distCW = (c1.h >= c2.h) ? 1 + c2.h - c1.h : c2.h - c1.h;
// ensure we get the right number of steps by adding remainder to final part
if (col == parts - 1) partSteps += remainder;
// make gradient for this part
for (var step = 0; step < partSteps; step ++) {
var p = step / partSteps;
// interpolate h, s, b
var h = (distCW <= distCCW) ? c1.h + (distCW * p) : c1.h - (distCCW * p);
if (h < 0) h = 1 + h;
if (h > 1) h = h - 1;
var s = (1 - p) * c1.s + p * c2.s;
var b = (1 - p) * c1.b + p * c2.b;
// add to gradient array
gradient[gradientIndex] = {h:h, s:s, b:b};
gradientIndex ++;
}
}
return gradient;
}
You should just need to find out which is the shortest path from starting hue to ending hue. This can be done easily since hue values range from 0 to 255.
You can first subtract the lower hue from the higher one, then add 256 to the lower one to check again the difference with swapped operands.
int maxCCW = higherHue - lowerHue;
int maxCW = (lowerHue+256) - higherHue;
So you'll obtain two values, the greater one decides if you should go clockwise or counterclockwise. Then you'll have to find a way to make the interpolation operate on modulo 256 of the hue, so if you are interpolating from 246 to 20 if the coefficient is >= 0.5f you should reset hue to 0 (since it reaches 256 and hue = hue%256 in any case).
Actually if you don't care about hue while interpolating over the 0 but just apply modulo operator after calculating the new hue it should work anyway.
Although this answer is late, the accepted one is incorrect in stating that hue should be within [0, 255]; also more justice can be done with clearer explanation and code.
Hue is an angular value in the interval [0, 360); a full circle where 0 = 360. The HSV colour space is easier to visualize and is more intuitive to humans then RGB. HSV forms a cylinder from which a slice is shown in many colour pickers, while RGB is really a cube and isn't really a good choice for a colour picker; most ones which do use it would have to employ more sliders than required for a HSV picker.
The requirement when interpolating hue is that the smaller arc is chosen to reach from one hue to another. So given two hue values, there are four possibilities, given with example angles below:
Δ | ≤ 180 | > 180
--|---------|---------
+ | 40, 60 | 310, 10
− | 60, 40 | 10, 310
if Δ = 180 then both +/− rotation are valid options
Lets take + as counter-clockwise and − as clockwise rotation. If the difference in absolute value exceeds 180 then normalize it by ± 360 to make sure the magnitude is within 180; this also reverses the direction, rightly.
var d = h2 - h1;
var delta = d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0);
Now just divide delta by the required number of steps to get the weight of each loop iteration to add to the start angle during interpolating.
var new_angle = start + (i * delta);
Relevant function excerpted from the complete code that follows:
function interpolate(h1, h2, steps) {
var d = h2 - h1;
var delta = (d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0)) / (steps + 1.0);
var turns = [];
for (var i = 1; d && i <= steps; ++i)
turns.push(((h1 + (delta * i)) + 360) % 360);
return turns;
}
"use strict";
function interpolate(h1, h2, steps) {
var d = h2 - h1;
var delta = (d + ((Math.abs(d) > 180) ? ((d < 0) ? 360 : -360) : 0)) / (steps + 1.0);
var turns = [];
for (var i = 1; d && i <= steps; ++i)
turns.push(((h1 + (delta * i)) + 360) % 360);
return turns;
}
function get_results(h1, h2, steps) {
h1 = norm_angle(h1);
h2 = norm_angle(h2);
var r = "Start: " + h1 + "<br />";
var turns = interpolate(h1, h2, steps);
r += turns.length ? "Turn: " : "";
r += turns.join("<br />Turn: ");
r += (turns.length ? "<br />" : "") + "Stop: " + h2;
return r;
}
function run() {
var h1 = get_angle(document.getElementById('h1').value);
var h2 = get_angle(document.getElementById('h2').value);
var steps = get_num(document.getElementById('steps').value);
var result = get_results(h1, h2, steps);
document.getElementById('res').innerHTML = result;
}
function get_num(s) {
var n = parseFloat(s);
return (isNaN(n) || !isFinite(n)) ? 0 : n;
}
function get_angle(s) {
return get_num(s) % 360;
}
function norm_angle(a) {
a %= 360;
a += (a < 0) ? 360 : 0;
return a;
}
<h1 id="title">Hue Interpolation</h1>
Angle 1
<input type="text" id="h1" />
<br />Angle 2
<input type="text" id="h2" />
<br />
<br />Intermediate steps
<input type="text" id="steps" value="5" />
<br />
<br/>
<input type="submit" value="Run" onclick="run()" />
<p id="res"></p>