-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
414 lines (372 loc) · 14.1 KB
/
script.js
File metadata and controls
414 lines (372 loc) · 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/*
Title: Color Picker
Description: Allows a user to pick or enter custom colors and view related
colors.
Last Updated: June 8, 2023
Developer: Alexander Beck
Email: beckhv2@gmail.com
Github: https://github.com/bexcoding
*/
// counter for naming id of saved colors
let savedColorCounter = 0;
// updates page on loading to create base appearance
window.addEventListener('load', () => {
updateBackground('#66087A');
updateColorValues('#66087A');
updateRelated();
});
// monitors dropdown menu for changes
document.getElementById('related').addEventListener('change', updateRelated);
// updates page based on selected color from expanding color picker
document.getElementById('color-picker').addEventListener('change', () => {
const currentColor = document.getElementById('color-picker').value;
updateBackground(currentColor);
updateColorValues(currentColor);
updateRelated();
document.getElementById('current-color-display').style.backgroundColor =
currentColor;
});
// allows current main displayed color to be saved by clicking on it
document.getElementById('current-color-display').addEventListener('click', () => {
const current = document.getElementById('color-picker').value;
saveColor(current.toUpperCase());
});
/**
* saves a given color at the bottom of the page
* @param {string} hex - string of hex color (example: '#F33D70')
*/
function saveColor(hex) {
// counter tracks number of saved colors for unique id naming
savedColorCounter += 1;
// creates a rectangle in the save area with the given hex color
const savedColor = document.createElement('div');
savedColor.setAttribute('class', 'saved-color');
savedColor.setAttribute('id', `saved-color-${savedColorCounter}`);
savedColor.style.backgroundColor = hex;
savedColor.style.color = hex;
document.getElementById('saved-colors').appendChild(savedColor);
// creates the text/name of the saved color
const savedColorText = document.createElement('div');
savedColorText.setAttribute('class', 'saved-text');
savedColorText.innerHTML = hex;
document.getElementById(`saved-color-${savedColorCounter}`).appendChild(savedColorText);
}
/**
* updates the related colors section based on the dropdown menu choice
*/
function updateRelated() {
// resets the display area before making a new palette
const color = document.getElementById('color-picker').value;
resetDisplay(document.getElementById('related-color-display'));
const mainColor = rgbToHsl(hexToRgb(color));
const colorType = document.getElementById('related').value;
makePalette(colorType, mainColor);
/**
* resets the display area for the related colors section
* @param parent - the selector of the area that needs to be cleared
*/
function resetDisplay(parent) {
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
};
}
/**
* makes a new color square in the related color area
* @param {string} hex - string of hex color (example: '#F33D70')
*/
function makeSquare(hex) {
// creates a color square
const square = document.createElement('div');
square.setAttribute('class', 'color-tile');
square.setAttribute('id', `${hex}`);
square.setAttribute('onclick', `saveColor("${hex.toUpperCase()}")`);
document.getElementById('related-color-display').appendChild(square);
// creates the top of the square which shows the color
const top = document.createElement('div');
top.setAttribute('class', 'tile-top');
top.style.backgroundColor = hex;
document.getElementById(`${hex}`).appendChild(top);
// creates the bottom the square which displays the name of the color
const bottom = document.createElement('div');
bottom.setAttribute('class', 'tile-bottom');
bottom.innerHTML = hex;
document.getElementById(`${hex}`).appendChild(bottom);
}
/**
* creates the number and color of squares based on the dropdown menu
* @param {string} relation - any of the dropdown menu choices
* @param {HSL object} mainColor - the main color as an hsl object
*/
function makePalette(relation, mainColor) {
const mainHex = rgbToHex(hslToRgb(mainColor));
// each if/else creates the number of squares needed for the option
if (relation === 'complimentary') {
const complement = new Hsl(((mainColor.hue + 180) % 360), mainColor.saturation, mainColor.lightness);
makeSquare(mainHex);
makeSquare(rgbToHex(hslToRgb(complement)));
} else if (relation === 'triadic') {
const second = new Hsl(((mainColor.hue + 120) % 360), mainColor.saturation, mainColor.lightness);
const third = new Hsl(((mainColor.hue + 240) % 360), mainColor.saturation, mainColor.lightness);
makeSquare(mainHex);
makeSquare(rgbToHex(hslToRgb(second)));
makeSquare(rgbToHex(hslToRgb(third)));
} else if (relation === 'tetradic') {
const tetra2 = new Hsl(((mainColor.hue + 90) % 360), mainColor.saturation, mainColor.lightness);
const tetra3 = new Hsl(((mainColor.hue + 180) % 360), mainColor.saturation, mainColor.lightness);
const tetra4 = new Hsl(((mainColor.hue + 270) % 360), mainColor.saturation, mainColor.lightness);
makeSquare(mainHex);
makeSquare(rgbToHex(hslToRgb(tetra2)));
makeSquare(rgbToHex(hslToRgb(tetra3)));
makeSquare(rgbToHex(hslToRgb(tetra4)));
} else if (relation === 'hues') {
let currentHue = mainColor.hue;
for (let i = 0; i < 8; i++) {
makeSquare(rgbToHex(hslToRgb(new Hsl((currentHue % 360), mainColor.saturation, mainColor.lightness))));
currentHue = currentHue + 45;
};
} else if (relation === 'saturation') {
let currentSat = 0;
for (let i = 0; i < 8; i++) {
makeSquare(rgbToHex(hslToRgb(new Hsl(mainColor.hue, currentSat, mainColor.lightness))));
currentSat = currentSat + 0.12;
};
} else {
let currentLight = 0;
for (let i = 0; i < 8; i++) {
makeSquare(rgbToHex(hslToRgb(new Hsl(mainColor.hue, mainColor.saturation, currentLight))));
currentLight = currentLight + 0.12;
};
};
}
}
/**
* updates the background of the page with a color similar to the main color
* @param {string} color - string of hex color (example: '#F33D70')
*/
function updateBackground(color) {
// converts hex to hsl
const converted = rgbToHsl(hexToRgb(color));
const hue = converted.hue;
const sat = converted.saturation;
// updates background colors with same hue and sat but with 90% lightness
document.getElementById('selection-area').style.backgroundColor = `hsl(${hue}, ${sat * 100}%, 90%)`;
document.getElementById('saved-colors').style.backgroundColor = `hsl(${hue}, ${sat * 100}%, 90%)`;
document.getElementById('current-color-values').style.backgroundColor = `hsl(${hue}, ${sat * 100}%, 90%)`;
}
/**
* changes the displayed rgb, hex, and hsl values for the selected color
* @param {string} color - string of hex color (example: '#F33D70')
*/
function updateColorValues(color) {
const rgb = hexToRgb(color);
const red = rgb.red;
const green = rgb.green;
const blue = rgb.blue;
const hsl = rgbToHsl(rgb);
const hue = hsl.hue;
const sat = hsl.saturation;
const light = hsl.lightness;
document.getElementById('hsl-color-val').innerHTML = `HSL: ${hue}, ${Math.round(sat * 100)}%, ${Math.round(light * 100)}%`;
document.getElementById('rgb-color-val').innerHTML = `RGB: ${red}, ${green}, ${blue}`;
document.getElementById('hex-color-val').innerHTML = `HEX: ${color.toUpperCase()}`;
}
/**
* template for creating an hsl object
* @param {number} h - value for hue
* @param {number} s - value for saturation
* @param {number} l - value for lightness
*/
function Hsl(h, s, l) {
this.hue = h;
this.saturation = s;
this.lightness = l;
}
/**
* template for creating an rgb object
* @param {number} r - value for red
* @param {number} g - value for green
* @param {number} b - value for blue
*/
function Rgb(r, g, b) {
this.red = r;
this.green = g;
this.blue = b;
}
/**
* checks if the given hsl object has valid values
* @param {HSL object} hslObject - the main color as an hsl object
* @returns {boolean} - returns true if each value is in the correct range
*/
function checkHsl(hslObject) {
return ((hslObject.hue >= 0 && hslObject.hue <= 360) &&
(hslObject.saturation >= 0 && hslObject.saturation <= 1) &&
(hslObject.lightness >= 0 && hslObject.lightness <= 1));
}
/**
* converts an hsl object to an rgb object
* @param {HSL object} hslValue the main color as an hsl object
* @returns {RGB object} the converted color in rgb
*/
function hslToRgb(hslValue) {
// if the given value is a valid hsl object, does the math to convert it
if (checkHsl(hslValue)) {
const c = (1 - Math.abs((2 * hslValue.lightness) - 1)) * hslValue.saturation;
const hPrime = hslValue.hue / 60;
const x = c * (1 - Math.abs(hPrime % 2 - 1));
const m = hslValue.lightness - (c / 2);
let r1 = 0;
let g1 = 0;
let b1 = 0;
if (hPrime >= 0 && hPrime <= 1) {
r1 = c;
g1 = x;
} else if (hPrime >= 1 && hPrime <= 2) {
r1 = x;
g1 = c;
} else if (hPrime >= 2 && hPrime <= 3) {
g1 = c;
b1 = x;
} else if (hPrime >= 3 && hPrime <= 4) {
g1 = x;
b1 = c;
} else if (hPrime >= 4 && hPrime <= 5) {
r1 = x;
b1 = c;
} else {
r1 = c;
b1 = x;
};
const red = Math.round((r1 + m) * 255);
const green = Math.round((g1 + m) * 255);
const blue = Math.round((b1 + m) * 255);
return new Rgb(red, green, blue);
} else {
console.log("HSL object is invalid");
};
}
/**
* converts an rgb object to a hex color string
* @param {RGB object} rgbObject a color represented as an rgb object
*/
function rgbToHex(rgbObject) {
let hexString = "#";
hexString += toHexadecimal(rgbObject.red);
hexString += toHexadecimal(rgbObject.green);
hexString += toHexadecimal(rgbObject.blue);
return hexString;
/**
* converts a decimal number to hexadecimal
* @param {number} decimal decimal number (example: 10)
* @returns {string} two hex characters (example: 'FF')
*/
function toHexadecimal(decimal) {
// create first hex string
let first = Math.floor(decimal / 16);
first = numToString(first);
// create second hex string
let second = decimal % 16;
second = numToString(second);
return first + second;
}
/**
* converts hexadecimal numbers to strings
* @param {number} num the number from the converted rgb value
* @returns {string} a number as a string or a number 10-15 as a letter
*/
function numToString(num) {
if (num < 10) {
return num.toString();
} else if (num === 10) {
return "A";
} else if (num === 11) {
return "B";
} else if (num === 12) {
return "C";
} else if (num === 13) {
return "D";
} else if (num === 14) {
return "E";
} else {
return "F";
};
}
}
/**
* converts a hex color string to an rgb object
* @param {string} hexValue a hex string of a color (example: '#A8D900')
* @returns {RGB object} a converted color as an rgb object
*/
function hexToRgb(hexValue) {
let rgbValue = hexValue.slice(1);
const red = toDecimal(rgbValue.slice(0,2));
const green = toDecimal(rgbValue.slice(2,4));
const blue = toDecimal(rgbValue.slice(4));
return new Rgb(red, green, blue);
/**
* converts a pair of hexadecimal string characters to a decimal number
* @param {string} hexadecimal two hex characters (example: 'FF')
* @returns {number} a decimal number (example: 0 - 255)
*/
function toDecimal(hexadecimal) {
let first = stringToNum(hexadecimal[0]) * 16;
let second = stringToNum(hexadecimal[1]);
return first + second;
}
/**
* converts a hexadecimal string to a decimal number
* @param {string} string (example: 'F' or '13')
* @returns {number} converted number (example: number 0 - 15)
*/
function stringToNum(string) {
string = string.toUpperCase();
if (string === "A") {
return 10;
} else if (string === "B") {
return 11;
} else if (string === "C") {
return 12;
} else if (string === "D") {
return 13;
} else if (string === "E") {
return 14;
} else if (string === "F") {
return 15;
} else {
return Number(string);
};
}
}
/**
* converts an rgb object to an hsl object
* @param {RGB object} rgbValue a color represented with an rgb object
* @returns {HSL object} a color represented with an hsl object
*/
function rgbToHsl(rgbValue) {
const r1 = rgbValue.red / 255;
const g1 = rgbValue.green / 255;
const b1 = rgbValue.blue / 255;
const cMax = Math.max(r1, g1, b1);
const cMin = Math.min(r1, g1, b1);
const cDelta = cMax - cMin;
let hue = 0;
let saturation = 0;
let lightness = (cMax + cMin) / 2;
lightness = Math.round(lightness * 100) / 100;
if (cDelta != 0) {
saturation = cDelta / (1 - Math.abs((2 * lightness) - 1));
if (cMax === r1) {
hue = ((g1 - b1) / cDelta) % 6;
} else if (cMax === g1) {
hue = ((b1 - r1) / cDelta) + 2;
} else if (cMax === b1) {
hue = ((r1 - g1) / cDelta) + 4;
};
hue *= 60;
if (hue < 0) {
hue += 360;
};
saturation = Math.round(saturation * 100) / 100;
hue = Math.round(hue);
};
return new Hsl(hue, saturation, lightness);
}