Fully functional Colorpicker with Preview

This commit is contained in:
Conor_Mack 2020-06-12 10:48:20 +01:00
parent ed1b30d83a
commit ebc47a9b1b
10 changed files with 510 additions and 259 deletions

View File

@ -0,0 +1,27 @@
<script>
import FlatButton from "./FlatButton.svelte";
export let format = "hex";
export let onclick = format => {};
let colorFormats = ["hex", "rgb", "hsl"];
</script>
<style>
.flatbutton-group {
font-weight: 500;
display: flex;
flex-flow: row nowrap;
width: 100%;
justify-content: center;
}
</style>
<div class="flatbutton-group">
{#each colorFormats as text}
<FlatButton
selected={format === text}
{text}
on:click={() => onclick(text)} />
{/each}
</div>

View File

@ -1,10 +1,17 @@
<script>
import {onMount} from "svelte"
import { getAndConvertHexa, getAndConvertRgba, getHSLA, hsvaToHexa, hsvaToRgba, getColorFormat, convertToHSVA } from "./utils.js"
import { onMount, createEventDispatcher } from "svelte";
import {
getColorFormat,
convertToHSVA,
convertHsvaToFormat
} from "./utils.js";
import Slider from "./Slider.svelte";
import Palette from "./Palette.svelte";
import ButtonGroup from "./ButtonGroup.svelte";
import Input from "./Input.svelte";
export let value = "rgba(255,255,255,1)";
export let value = "#3ec1d3ff";
export let format = "hexa";
let h = null;
@ -12,24 +19,20 @@
let v = null;
let a = null;
const dispatch = createEventDispatcher();
onMount(() => {
format = getColorFormat(value)
if(format) {
let hsva = convertToHSVA(value, format)
setHSVA(hsva)
format = getColorFormat(value);
if (format) {
convertAndSetHSVA()
}
})
});
const hsvaIsNull = () => [h,s,v,a].every(c => c === null)
const hsvaIsNull = () => [h, s, v, a].every(c => c === null);
function setFormatAndConvert() {
if (value.startsWith('#')) {
format = "hexa"
return getAndConvertHexa(value)
} else if (value.startsWith('rgba')) {
format = "rgba"
return getAndConvertRgba(value)
}
function convertAndSetHSVA() {
let hsva = convertToHSVA(value, format);
setHSVA(hsva);
}
function setHSVA([hue, sat, val, alpha]) {
@ -40,53 +43,81 @@
}
//fired by choosing a color from the palette
function setSaturationAndValue({detail}) {
s = detail.s
v = detail.v
let res = convertHSVA()
console.log("SAT-VAL", res)
function setSaturationAndValue({ detail }) {
s = detail.s;
v = detail.v;
value = convertHsvaToFormat([h, s, v, a], format);
dispatch("change", value)
}
function setHue(hue) {
h = hue
let res = convertHSVA()
console.log("HUE",res)
h = hue;
value = convertHsvaToFormat([h, s, v, a], format);
dispatch("change", value)
}
function setAlpha(alpha) {
a = alpha
let res = convertHSVA()
console.log("ALPHA",res)
a = alpha === "1.00" ? "1" :alpha;
value = convertHsvaToFormat([h, s, v, a], format);
dispatch("change", value)
}
function convertHSVA() {
let hsva = [h, s, v, a]
let _value = format === "hexa" ? hsvaToHexa(hsva, true) : hsvaToRgba(hsva, true)
return _value;
// onchange(_value)
function changeFormatAndConvert(f) {
format = f;
value = convertHsvaToFormat([h, s, v, a], format);
}
// $: {
// if(!hsvaIsNull()) {
// let hsva = [h, s, v, a]
// // let t = value + "abs"
// value = format === "hexa" ? hsvaToHexa(hsva) : hsvaToRgba(hsva)
// debugger
// // console.log("VAL", value)
// }
// }
function handleColorInput(text) {
let f = getColorFormat(text)
if(f) {
format = f;
value = text
convertAndSetHSVA()
}
}
</script>
<style>
.colorpicker-container {
display: flex;
font-size: 12px;
font-weight: 400;
flex-direction: column;
height: 300px;
width: 250px;
background: #ffffff;
border: 1px solid #e8e8ef;
border-radius: 2px;
box-shadow: 0 0.15em 1.5em 0 rgba(0,0,0,.1), 0 0 1em 0 rgba(0,0,0,.03);
}
.control-panel {
display: flex;
flex-direction: column;
padding: 8px;
background: white;
border: 1px solid #d2d2d2
}
.alpha-hue-panel {
display: grid;
grid-template-columns: 25px 1fr;
grid-gap: 15px;
justify-content: center;
align-items: center;
/* padding: 8px; */
}
.selected-color {
width: 30px;
height: 30px;
border-radius: 50%;
border: 1px solid #dedada;
}
.format-input-panel {
display: flex;
flex-direction: column;
justify-content: center;
}
</style>
@ -94,7 +125,24 @@
<Palette on:change={setSaturationAndValue} {h} {s} {v} {a} />
<Slider type="hue" value={h} on:change={hue => setHue(hue.detail)} />
<div class="control-panel">
<div class="alpha-hue-panel">
<div>
<div class="selected-color" style={`background: ${value}`} />
</div>
<div>
<Slider type="hue" value={h} on:change={hue => setHue(hue.detail)} />
<Slider
type="alpha"
value={a}
on:change={alpha => setAlpha(alpha.detail)} />
</div>
</div>
<div class="format-input-panel">
<ButtonGroup {format} onclick={changeFormatAndConvert} />
<Input {value} on:input={event => handleColorInput(event.target.value)} />
</div>
</div>
<Slider type="alpha" value={a} on:change={alpha => setAlpha(alpha.detail)} />
</div>

View File

@ -0,0 +1,78 @@
<script>
import Colorpicker from "./Colorpicker.svelte"
import {createEventDispatcher} from "svelte"
import {buildStyle} from "./helpers.js"
import { fade } from 'svelte/transition';
export let value = "#3ec1d3ff"
export let format = "hexa";
export let width = "25px"
export let open = true;
export let fullwidth = false;
let colorPreview = null
let positionSide = "top"
$: width = fullwidth ? "100%" : width
$: style = buildStyle({width, background: value})
$: colorStyle = buildStyle({[positionSide]: `28px`})
const dispatch = createEventDispatcher()
function openColorpicker(event) {
if(colorPreview) {
const {top: spaceAbove, width, bottom} = colorPreview.getBoundingClientRect()
const spaceBelow = window.innerHeight - bottom;
if (spaceAbove > spaceBelow) {
positionSide = "bottom"
} else {
positionSide = "top"
}
}
open = true;
}
function onColorChange(color) {
value = color.detail;
dispatch("change", color.detail)
}
</script>
<div class="color-preview-container">
<div bind:this={colorPreview} class="color-preview" {style} on:click={openColorpicker}></div>
{#if open}
<div class="color-preview" style={colorStyle}>
<Colorpicker on:change={onColorChange} {format} {value} />
</div>
{/if}
</div>
{#if open}
<div on:click|self={() => open = false} class="overlay"></div>
{/if}
<style>
.color-preview-container{
position: relative;
display: flex;
flex-flow: row nowrap;
height: fit-content;
}
.color-preview {
position: absolute;
flex: 1;
height: 25px;
z-index: 2;
border-radius: 3px;
}
.overlay{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
</style>

View File

@ -0,0 +1,26 @@
<script>
export let text = "";
export let selected = false;
</script>
<style>
.flatbutton {
padding: 3px 15px;
cursor: pointer;
color: black;
background-color: #dadada;
border: 1px solid #d4d4d4;
border-radius: 8px;
text-transform: uppercase;
margin: 5px;
transition: all 0.3s;
}
.selected {
color: #ffffff;
background-color: #003cb0;
border: none;
}
</style>
<div class="flatbutton" class:selected on:click>{text}</div>

View File

@ -0,0 +1,28 @@
<script>
export let value = "";
</script>
<style>
div {
display: flex;
justify-content: center;
margin: 5px 0px;
}
input {
width: 185px;
font-size: 14px;
background: #f1f3f4;
border-radius: 8px;
height: 27px;
outline-color: #003cb0;
color: #565252;
text-align: center;
/* border: none; */
border: 1px solid #dadada;
}
</style>
<div>
<input on:input type="text" {value} maxlength="25" />
</div>

View File

@ -42,6 +42,7 @@
width: 100%;
height: 175px;
cursor: crosshair;
overflow: hidden;
}
.picker {

View File

@ -2,7 +2,7 @@
import { onMount, createEventDispatcher } from "svelte";
import dragable from "./drag.js";
export let value = 1
export let value = 1;
export let type = "hue";
const dispatch = createEventDispatcher();
@ -11,20 +11,22 @@
let sliderWidth = 0;
function handleClick(mouseX) {
const { left } = slider.getBoundingClientRect();
const { left, width } = slider.getBoundingClientRect();
let clickPosition = mouseX - left;
let percentageClick = (clickPosition / sliderWidth).toFixed(2)
if (clickPosition >= 0 && clickPosition <= sliderWidth) {
let percentageClick = clickPosition / sliderWidth;
if (percentageClick >= 0 && percentageClick <= 1) {
let value =
type === "hue"
? 360 * percentageClick.toString()
: percentageClick.toString();
? 360 * percentageClick
: percentageClick;
dispatch("change", value);
}
}
$: thumbPosition = type === "hue" ? sliderWidth * (value / 360) : sliderWidth * (value)
$: thumbPosition =
type === "hue" ? sliderWidth * (value / 360) : sliderWidth * value;
$: style = `transform: translateX(${thumbPosition - 6}px);`;
</script>
@ -34,10 +36,11 @@
position: relative;
align-self: center;
height: 8px;
width: 220px;
width: 185px;
border-radius: 10px;
margin: 10px 0px;
border: 1px solid #e8e8ef;
cursor: pointer;
}
.hue {
@ -62,9 +65,10 @@
bottom: -3px;
height: 12px;
width: 12px;
border: 1px solid black;
border: 1px solid #777676;
border-radius: 50%;
background-color: #ffffff;
cursor:grab;
}
</style>

View File

@ -0,0 +1,14 @@
export const buildStyle = styles => {
let str = ""
for (let s in styles) {
if (styles[s]) {
let key = convertCamel(s)
str += `${key}: ${styles[s]}; `
}
}
return str
}
export const convertCamel = str => {
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
}

View File

@ -1,2 +1,3 @@
import Colorpicker from './Colorpicker.svelte';
export default Colorpicker;
import Colorpreview from './Colorpreview.svelte';
export default Colorpreview;

View File

@ -1,244 +1,268 @@
export const isValidHex = (str) => /^#(?:[A-F0-9]{3}$|[A-F0-9]{6}$|[A-F0-9]{8})$/gi.test(str)
export const isValidHex = str =>
/^#(?:[A-F0-9]{3}$|[A-F0-9]{4}$|[A-F0-9]{6}$|[A-F0-9]{8})$/gi.test(str);
const getHexaValues = (hexString) => hexString.match(/[A-F0-9]{2}/gi);
export const isValidRgb = (str) => {
const hasValidStructure = /^(?:rgba\(|rgb\()[0-9,.\s]*\)$/gi.test(str);
if(hasValidStructure) {
return testRgbaValues(str.toLowerCase());
}
}
const findNonNumericChars = /[a-z()%\s]/gi
export const getNumericValues = (str) => str.replace(findNonNumericChars, '').split(',').map(c => Number(c));
export const testRgbaValues = (str) => {
const rgba = getNumericValues(str)
let [ r, g, b, a ] = rgba;
let isValidLengthRange = (str.startsWith("rgb(") && rgba.length === 3) || (str.startsWith("rgba(") && rgba.length === 4);
let isValidColorRange = [ r, g, b ].every((v) => v >= 0 && v <= 255);
let isValidAlphaRange = str.startsWith("rgba(") ? a >= 0 && a <= 1 : true;
return isValidLengthRange && isValidColorRange && isValidAlphaRange;
const getHexaValues = hexString => {
if (hexString.length <= 5) {
let hexArr = hexString.match(/[A-F0-9]/gi);
let t = hexArr.map(c => (c += c));
return t;
} else {
return hexString.match(/[A-F0-9]{2}/gi);
}
};
export const isValidHsl = (str) => {
const hasValidStructure = /^(?:hsl\(|hsla\()[0-9,.\s]*\)$/gi.test(str)
if(hasValidStructure) {
return testHslaValues(str.toLowerCase())
}
}
export const isValidRgb = str => {
const hasValidStructure = /^(?:rgba\(|rgb\()(?:[0-9,\s]|\.(?=\d))*\)$/gi.test(str);
if (hasValidStructure) {
return testRgbaValues(str.toLowerCase());
}
};
export const testHslaValues = (str) => {
const findNonNumericChars = /[a-z()\s]/gi;
const hsla = getNumericValues(str)
const [h, s, l, a] = hsla
export const getNumericValues = str =>
str
.replace(findNonNumericChars, "")
.split(",")
.map(v => v !== "" ? v : undefined);
let isValidLengthRange = (str.startsWith("hsl(") && hsla.length === 3) || (str.startsWith("hsla(") && hsla.length === 4);
let isValidColorRange = (h >= 0 && h <= 360) && [s, l].every(v => v >= 0 && v <= 100)
let isValidAlphaRange = str.startsWith("hsla(") ? (a >= 0 && a <= 1) : true
export const testRgbaValues = str => {
const rgba = getNumericValues(str);
const [r, g, b, a] = rgba;
let isValidLengthRange =
(str.startsWith("rgb(") && rgba.length === 3) ||
(str.startsWith("rgba(") && rgba.length === 4);
let isValidColorRange = [r, g, b].every(v => v >= 0 && v <= 255);
let isValidAlphaRange = str.startsWith("rgba(") ? `${a}`.length <= 4 && a >= 0 && a <= 1 : true;
return isValidLengthRange && isValidColorRange && isValidAlphaRange;
}
return isValidLengthRange && isValidColorRange && isValidAlphaRange;
};
export const getColorFormat = (color) => {
if(typeof color === "string") {
if(isValidHex(color)) {
return 'hex'
}else if(isValidRgb(color)) {
return 'rgb'
}else if(isValidHsl(color)) {
return 'hsl'
}
}
}
export const isValidHsl = str => {
const hasValidStructure = /^(?:hsl\(|hsla\()(?:[0-9,%\s]|\.(?=\d))*\)$/gi.test(str);
if (hasValidStructure) {
return testHslaValues(str.toLowerCase());
}
};
export const testHslaValues = str => {
const hsla = getNumericValues(str);
const [h, s, l, a] = hsla;
const isUndefined = [h,s,l].some(v => v === undefined)
if(isUndefined) return false;
let isValidLengthRange =
(str.startsWith("hsl(") && hsla.length === 3) ||
(str.startsWith("hsla(") && hsla.length === 4);
let isValidHue = h >= 0 && h <= 360
let isValidSatLum = [s, l].every(v => v.endsWith('%') && parseInt(v) >= 0 && parseInt(v) <= 100 )
let isValidAlphaRange = str.startsWith("hsla(") ? `${a}`.length <= 4 && a >= 0 && a <= 1 : true;
return isValidLengthRange && isValidHue && isValidSatLum && isValidAlphaRange;
};
export const getColorFormat = color => {
if (typeof color === "string") {
if (isValidHex(color)) {
return "hex";
} else if (isValidRgb(color)) {
return "rgb";
} else if (isValidHsl(color)) {
return "hsl";
}
}
};
export const convertToHSVA = (value, format) => {
switch(format) {
case "hex":
return getAndConvertHexa(value)
case "rgb":
return getAndConvertRgba(value)
case "hsl":
return getAndConvertHsla(value)
}
}
switch (format) {
case "hex":
return getAndConvertHexa(value);
case "rgb":
return getAndConvertRgba(value);
case "hsl":
return getAndConvertHsla(value);
}
};
export const convertHsvaToFormat = (hsva, format) => {
switch(format) {
case "hex":
return hsvaToHexa(hsva, true)
case "rgb":
return hsvaToRgba(hsva, true)
case "hsl":
return hsvaToHsla(hsva, true)
}
}
switch (format) {
case "hex":
return hsvaToHexa(hsva, true);
case "rgb":
return hsvaToRgba(hsva, true);
case "hsl":
return hsvaToHsla(hsva);
}
};
export const getAndConvertHexa = (color) => {
let [ rHex, gHex, bHex, aHex ] = getHexaValues(color);
return hexaToHSVA([ rHex, gHex, bHex ], aHex);
}
export const getAndConvertHexa = color => {
let [rHex, gHex, bHex, aHex] = getHexaValues(color);
return hexaToHSVA([rHex, gHex, bHex], aHex);
};
export const getAndConvertRgba = color => {
let rgba = getNumericValues(color);
return rgbaToHSVA(rgba);
}
let rgba = getNumericValues(color);
return rgbaToHSVA(rgba);
};
export const getAndConvertHsla = color => {
let hsla = getNumericValues(color);
return hslaToHSVA(hsla)
}
export const getHSLA = ([hue, sat, val, a]) => {
const [ h, s, l ] = _hsvToHSL([hue, sat, val]);
return `hsla(${h}, ${s}, ${l}, ${a})`;
let hsla = getNumericValues(color);
return hslaToHSVA(hsla);
};
export const hexaToHSVA = (hex, alpha = 'FF') => {
const rgba = hex.map((v) => parseInt(v, 16)).concat(Number((parseInt(alpha, 16) / 255).toFixed(2)));
return rgbaToHSVA(rgba);
export const hexaToHSVA = (hex, alpha = "FF") => {
const rgba = hex
.map(v => parseInt(v, 16))
.concat(Number((parseInt(alpha, 16) / 255).toFixed(2)));
return rgbaToHSVA(rgba);
};
export const rgbaToHSVA = (rgba) => {
const [ r, g, b, a = 1 ] = rgba;
let hsv = _rgbToHSV([ r, g, b ]);
return [ ...hsv, a ];
export const rgbaToHSVA = rgba => {
const [r, g, b, a = 1] = rgba;
let hsv = _rgbToHSV([r, g, b]);
return [...hsv, a];
};
export const hslaToHSVA = ([h, s, l, a = 1]) => {
let hsv = _hslToHSV([h, s, l])
return [...hsv, a]
}
export const hsvaToHexa = (hsva, asString = false) => {
const [ r, g, b, a ] = hsvaToRgba(hsva);
const hexa = [ r, g, b ].map((v) => Math.round(v).toString(16)).concat(Math.round((a * 255)).toString(16));
return asString ? `#${hexa.join('')}` : hexa
let hsv = _hslToHSV([h, s, l]);
return [...hsv, a];
};
export const hsvaToRgba = ([h, s, v, a], asString = false) => {
let rgb = _hsvToRgb([ h, s, v ]).map(x => Math.round(x));
let rgba = [ ...rgb, a ];
return asString ? `rgba(${rgba.join(",")})` : rgba
export const hsvaToHexa = (hsva, asString = false) => {
const [r, g, b, a] = hsvaToRgba(hsva);
const hexa = [r, g, b]
.map(v => {
let hex = Math.round(v).toString(16)
return hex.length === 1 ? `0${hex}` : hex
})
.concat(Math.round(a * 255).toString(16));
return asString ? `#${hexa.join("")}` : hexa;
};
export const hsvaToRgba = ([h, s, v, a = 1], asString = false) => {
let rgb = _hsvToRgb([h, s, v]).map(x => Math.round(x));
let rgba = [...rgb, a < 1 ? _fixNum(a, 2) : a];
return asString ? `rgba(${rgba.join(",")})` : rgba;
};
export const hsvaToHsla = ([h, s, v, a = 1], asString = false) => {
let hsl = _hsvToHSL([h, s, v])
let hsla = [...hsl, a]
return asString ? `hsla(${hsla.join(",")})` : hsla
}
let [hue, sat, lum] = _hsvToHSL([h, s, v]);
let hsla = [hue, sat + "%", lum + "%", a < 1 ? _fixNum(a, 2) : a];
return `hsla(${hsla.join(",")})`;
};
export const _hslToHSV = (hsl) => {
const h = hsl[0];
let s = hsl[1] / 100;
let l = hsl[2] / 100;
let smin = s;
const lmin = Math.max(l, 0.01);
export const _hslToHSV = hsl => {
const h = hsl[0];
let s = hsl[1] / 100;
let l = hsl[2] / 100;
let smin = s;
const lmin = Math.max(l, 0.01);
l *= 2;
s *= (l <= 1) ? l : 2 - l;
smin *= lmin <= 1 ? lmin : 2 - lmin;
const v = (l + s) / 2;
const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
l *= 2;
s *= l <= 1 ? l : 2 - l;
smin *= lmin <= 1 ? lmin : 2 - lmin;
const v = (l + s) / 2;
const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
return [h, sv * 100, v * 100];
}
//Credit : https://github.com/Qix-/color-convert
export const _rgbToHSV = (rgb) => {
let rdif;
let gdif;
let bdif;
let h;
let s;
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
const v = Math.max(r, g, b);
const diff = v - Math.min(r, g, b);
const diffc = function(c) {
return (v - c) / 6 / diff + 1 / 2;
};
if (diff === 0) {
h = 0;
s = 0;
} else {
s = diff / v;
rdif = diffc(r);
gdif = diffc(g);
bdif = diffc(b);
if (r === v) {
h = bdif - gdif;
} else if (g === v) {
h = 1 / 3 + rdif - bdif;
} else if (b === v) {
h = 2 / 3 + gdif - rdif;
}
if (h < 0) {
h += 1;
} else if (h > 1) {
h -= 1;
}
}
const hsvResult = [ h * 360, s * 100, v * 100 ].map((v) => Math.round(v));
return hsvResult;
return [h, sv * 100, v * 100];
};
//Credit : https://github.com/Qix-/color-convert
export const _hsvToRgb = (hsv) => {
const h = hsv[0] / 60;
const s = hsv[1] / 100;
let v = hsv[2] / 100;
const hi = Math.floor(h) % 6;
export const _rgbToHSV = rgb => {
let rdif;
let gdif;
let bdif;
let h;
let s;
const f = h - Math.floor(h);
const p = 255 * v * (1 - s);
const q = 255 * v * (1 - s * f);
const t = 255 * v * (1 - s * (1 - f));
v *= 255;
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;
const v = Math.max(r, g, b);
const diff = v - Math.min(r, g, b);
const diffc = function(c) {
return (v - c) / 6 / diff + 1 / 2;
};
switch (hi) {
case 0:
return [ v, t, p ];
case 1:
return [ q, v, p ];
case 2:
return [ p, v, t ];
case 3:
return [ p, q, v ];
case 4:
return [ t, p, v ];
case 5:
return [ v, p, q ];
}
if (diff === 0) {
h = 0;
s = 0;
} else {
s = diff / v;
rdif = diffc(r);
gdif = diffc(g);
bdif = diffc(b);
if (r === v) {
h = bdif - gdif;
} else if (g === v) {
h = 1 / 3 + rdif - bdif;
} else if (b === v) {
h = 2 / 3 + gdif - rdif;
}
if (h < 0) {
h += 1;
} else if (h > 1) {
h -= 1;
}
}
const hsvResult = [h * 360, s * 100, v * 100].map(v => Math.round(v));
return hsvResult;
};
//Credit : https://github.com/Qix-/color-convert
export const _hsvToHSL = (hsv) => {
const h = hsv[0];
const s = hsv[1] / 100;
const v = hsv[2] / 100;
const vmin = Math.max(v, 0.01);
let sl;
let l;
export const _hsvToRgb = hsv => {
const h = hsv[0] / 60;
const s = hsv[1] / 100;
let v = hsv[2] / 100;
const hi = Math.floor(h) % 6;
l = (2 - s) * v;
const lmin = (2 - s) * vmin;
sl = s * vmin;
sl /= lmin <= 1 ? lmin : 2 - lmin;
sl = sl || 0;
l /= 2;
const f = h - Math.floor(h);
const p = 255 * v * (1 - s);
const q = 255 * v * (1 - s * f);
const t = 255 * v * (1 - s * (1 - f));
v *= 255;
return [ h, Number((sl * 100).toFixed(1)), Number((l * 100).toFixed(1)) ];
switch (hi) {
case 0:
return [v, t, p];
case 1:
return [q, v, p];
case 2:
return [p, v, t];
case 3:
return [p, q, v];
case 4:
return [t, p, v];
case 5:
return [v, p, q];
}
};
//Credit : https://github.com/Qix-/color-convert
export const _hsvToHSL = hsv => {
const h = hsv[0];
const s = hsv[1] / 100;
const v = hsv[2] / 100;
const vmin = Math.max(v, 0.01);
let sl;
let l;
l = (2 - s) * v;
const lmin = (2 - s) * vmin;
sl = s * vmin;
sl /= lmin <= 1 ? lmin : 2 - lmin;
sl = sl || 0;
l /= 2;
return [_fixNum(h, 0), _fixNum(sl * 100, 0), _fixNum(l * 100, 0)];
};
export const _fixNum = (value, decimalPlaces) =>
Number(parseFloat(value).toFixed(decimalPlaces));