Palette, Slider Components and Util Updates
This commit is contained in:
parent
28307c27b8
commit
4ef62452ef
|
@ -0,0 +1,32 @@
|
|||
<script>
|
||||
import Slider from "./Slider.svelte";
|
||||
import Palette from "./Palette.svelte";
|
||||
|
||||
export let value = "#00000000";
|
||||
|
||||
let h = 0;
|
||||
let s = 0;
|
||||
let v = 0;
|
||||
let a = 1;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.colorpicker-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 300px;
|
||||
width: 250px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e8e8ef;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="colorpicker-container">
|
||||
|
||||
<Palette {h} {a} />
|
||||
|
||||
<Slider type="hue" on:change={hue => (h = hue.detail)} />
|
||||
|
||||
<Slider type="alpha" on:change={alpha => (a = alpha.detail)} />
|
||||
</div>
|
|
@ -0,0 +1,49 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
export let h,
|
||||
a = 0;
|
||||
|
||||
let palette;
|
||||
let dimensions;
|
||||
|
||||
onMount(() => {
|
||||
if (palette) {
|
||||
dimensions = palette.getBoundingClientRect();
|
||||
}
|
||||
});
|
||||
|
||||
function handleClick(event) {
|
||||
const { left, top, width, height } = dimensions;
|
||||
let pickerX = (event.clientX - left) / width;
|
||||
let pickerY = (event.clientY - top) / height;
|
||||
//Saturation - adds white: pickerX * 100
|
||||
//value - adds black: 100 - pickerY * 100
|
||||
console.log("X", pickerX, "Y", pickerY);
|
||||
}
|
||||
|
||||
$: paletteGradient = `linear-gradient(to top, rgba(0, 0, 0, 1), transparent),
|
||||
linear-gradient(to left, hsla(${h}, 100%, 50%, ${a}), rgba(255, 255, 255, ${a}))
|
||||
`;
|
||||
$: style = `background: ${paletteGradient};`;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.palette {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 175px;
|
||||
}
|
||||
|
||||
.picker {
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: transparent;
|
||||
border: 2px solid white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div bind:this={palette} on:click={handleClick} class="palette" {style}>
|
||||
<div class="picker" />
|
||||
</div>
|
|
@ -0,0 +1,87 @@
|
|||
<script>
|
||||
import { onMount, createEventDispatcher } from "svelte";
|
||||
import dragable from "./drag.js";
|
||||
|
||||
export let type = "hue";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let slider;
|
||||
let dimensions = {};
|
||||
let thumbPosition = 0;
|
||||
|
||||
onMount(() => {
|
||||
if (slider) {
|
||||
dimensions = slider.getBoundingClientRect();
|
||||
}
|
||||
});
|
||||
|
||||
function handleClick(mouseX) {
|
||||
const { left, width } = dimensions;
|
||||
let clickPosition = mouseX - left;
|
||||
debugger;
|
||||
if (clickPosition >= 0 && clickPosition <= width) {
|
||||
thumbPosition = clickPosition;
|
||||
let percentageClick = thumbPosition / width;
|
||||
let value =
|
||||
type === "hue"
|
||||
? Math.round(360 * percentageClick).toString()
|
||||
: percentageClick.toFixed(2);
|
||||
dispatch("change", value);
|
||||
}
|
||||
}
|
||||
|
||||
$: style = `transform: translateX(${thumbPosition - 6}px);`;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.color-format-slider {
|
||||
position: relative;
|
||||
align-self: center;
|
||||
height: 8px;
|
||||
width: 220px;
|
||||
border-radius: 10px;
|
||||
margin: 10px 0px;
|
||||
border: 1px solid #e8e8ef;
|
||||
}
|
||||
|
||||
.hue {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
hsl(0, 100%, 50%),
|
||||
hsl(60, 100%, 50%),
|
||||
hsl(120, 100%, 50%),
|
||||
hsl(180, 100%, 50%),
|
||||
hsl(240, 100%, 50%),
|
||||
hsl(300, 100%, 50%),
|
||||
hsl(360, 100%, 50%)
|
||||
);
|
||||
}
|
||||
|
||||
.alpha {
|
||||
background: linear-gradient(to right, transparent, rgb(0 0 0));
|
||||
}
|
||||
|
||||
.slider-thumb {
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border: 1px solid black;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div
|
||||
bind:this={slider}
|
||||
on:click={event => handleClick(event.clientX)}
|
||||
class="color-format-slider"
|
||||
class:hue={type === 'hue'}
|
||||
class:alpha={type === 'alpha'}>
|
||||
<div
|
||||
use:dragable
|
||||
on:drag={e => handleClick(e.detail)}
|
||||
class="slider-thumb"
|
||||
{style} />
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
export default function(node) {
|
||||
function handleMouseDown() {
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
window.addEventListener('mouseup', handleMouseUp);
|
||||
}
|
||||
|
||||
function handleMouseMove(event) {
|
||||
let mouseX = event.clientX;
|
||||
console.log(mouseX);
|
||||
node.dispatchEvent(
|
||||
new CustomEvent('drag', {
|
||||
detail: mouseX
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function handleMouseUp() {
|
||||
window.removeEventListener('mousedown', handleMouseDown);
|
||||
window.removeEventListener('mousemove', handleMouseMove);
|
||||
}
|
||||
|
||||
node.addEventListener('mousedown', handleMouseDown);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
import Colorpicker from './Colorpicker.svelte';
|
||||
export default Colorpicker;
|
|
@ -0,0 +1,146 @@
|
|||
export const getRgbaValues = (rgbaString) => rgbaString.replace(/[a-z()\s]/gi, '').split(',');
|
||||
|
||||
export const getHexaValues = (hexString) => hexString.match(/[A-F]{2}|[A-F]\d{1}|\d{2}|\d[A-F]/gi);
|
||||
|
||||
export const isValidRgba = (rgba) => {
|
||||
let [ r, g, b, a = 1 ] = rgba;
|
||||
|
||||
let isValidLengthRange = rgba.length === 3 || rgba.length === 4;
|
||||
let isValidColorRange = [ r, g, b ].every((v) => v >= 0 && v <= 255);
|
||||
let isValidAlphaRange = rgba.length === 3 || (a >= 0 && a <= 1);
|
||||
|
||||
return isValidLengthRange && isValidColorRange && isValidAlphaRange;
|
||||
};
|
||||
|
||||
export const determineColorType = (color) => {
|
||||
let hsva = [];
|
||||
if (color.startsWith('#')) {
|
||||
let [ rHex, gHex, bHex, aHex ] = getHexaValues(color);
|
||||
hsva = hexaToHSVA([ rHex, gHex, bHex ], aHex);
|
||||
} else if (color.startsWith('rgb')) {
|
||||
let rgba = getRgbaValues(color);
|
||||
hsva = rgbaToHSVA(rgba);
|
||||
}
|
||||
};
|
||||
|
||||
export const getHSLA = (hsv, a) => {
|
||||
const [ h, s, l ] = hsvToHSL(hsv);
|
||||
return `hsla(${h}, ${s}, ${l}, ${a})`;
|
||||
};
|
||||
|
||||
export const hexaToHSVA = (hex, alpha = 'FF') => {
|
||||
const rgba = hex.map((v) => parseInt(v, 16)).concat((parseInt(alpha, 16) / 255).toFixed(1));
|
||||
return rgbaToHSVA(rgba);
|
||||
};
|
||||
|
||||
export const rgbaToHSVA = (rgba) => {
|
||||
if (isValidRgba(rgba)) {
|
||||
const [ r, g, b, a = '1' ] = rgba;
|
||||
let hsv = rgbToHSV([ r, g, b ]);
|
||||
return [ ...hsv, a ];
|
||||
}
|
||||
};
|
||||
|
||||
export const hsvaToHexa = () => {
|
||||
const [ r, g, b, a ] = hsvaToRgba();
|
||||
const hexa = [ r, g, b ].map((v) => v.toString(16)).concat((a * 255).toFixed(1).toString(16));
|
||||
return hexa;
|
||||
};
|
||||
|
||||
export const hsvaToRgba = (h, s, v, a) => {
|
||||
let rgb = _hsvToRgb([ h, s, v ]);
|
||||
return [ ...rgb, a ];
|
||||
};
|
||||
|
||||
//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) => v.toFixed(0));
|
||||
return hsvResult;
|
||||
};
|
||||
|
||||
//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;
|
||||
|
||||
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;
|
||||
|
||||
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 [ h, sl * 100, l * 100 ];
|
||||
};
|
|
@ -1,66 +0,0 @@
|
|||
import {
|
||||
getHexaValues,
|
||||
getRgbaValues,
|
||||
hsvToHSL,
|
||||
isValidRgba,
|
||||
rgbToHSV,
|
||||
hsvToRgb,
|
||||
} from "./utils"
|
||||
|
||||
export class HSVAColor {
|
||||
h = 0
|
||||
s = 0
|
||||
v = 0
|
||||
a = 1
|
||||
|
||||
constructor(color) {
|
||||
if (color.startsWith("#")) {
|
||||
let [rHex, gHex, bHex, aHex] = getHexaValues(color)
|
||||
this.hexaToHSVA([rHex, gHex, bHex], aHex)
|
||||
} else if (color.startsWith("rgb")) {
|
||||
let rgba = getRgbaValues(color)
|
||||
this.rgbaToHSVA(rgba)
|
||||
}
|
||||
}
|
||||
|
||||
setHSVA([h, s, v, a]) {
|
||||
this.h = h
|
||||
this.s = s
|
||||
this.v = v
|
||||
this.a = a
|
||||
}
|
||||
|
||||
getHSLA() {
|
||||
const [h, s, l] = hsvToHSL([this.h, this.s, this.v])
|
||||
return `hsla(${h}, ${s}, ${l}, ${this.a})`
|
||||
}
|
||||
|
||||
hexaToHSVA(hex, alpha = "FF") {
|
||||
const rgba = hex
|
||||
.map(v => parseInt(v, 16))
|
||||
.concat((parseInt(alpha, 16) / 255).toFixed(1))
|
||||
this.rgbaToHSVA(rgba)
|
||||
}
|
||||
|
||||
rgbaToHSVA(rgba) {
|
||||
if (isValidRgba(rgba)) {
|
||||
const [r, g, b, a = "1"] = rgba
|
||||
let hsv = rgbToHSV([r, g, b])
|
||||
this.setHSVA([...hsv, a])
|
||||
}
|
||||
}
|
||||
|
||||
hsvaToHexa() {
|
||||
const [r, g, b, a] = this.hsvaToRgba()
|
||||
const hexa = [r, g, b]
|
||||
.map(v => v.toString(16))
|
||||
.concat((a * 255).toFixed(1).toString(16))
|
||||
return hexa
|
||||
}
|
||||
|
||||
hsvaToRgba() {
|
||||
const { h, s, v, a } = this
|
||||
let rgb = hsvToRgb([h, s, v])
|
||||
return [...rgb, a]
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
export const getRgbaValues = rgbaString =>
|
||||
rgbaString.replace(/[a-z\(\)\s]/gi, "").split(",")
|
||||
|
||||
export const getHexaValues = hexString =>
|
||||
hexString.match(/[A-F]{2}|[A-F]\d{1}|\d{2}|\d[A-F]/gi)
|
||||
|
||||
export const isValidRgba = rgba => {
|
||||
let [r, g, b, a = 1] = rgba
|
||||
|
||||
let isValidLengthRange = rgba.length === 3 || rgba.length === 4
|
||||
let isValidColorRange = [r, g, b].every(v => v >= 0 && v <= 255)
|
||||
let isValidAlphaRange = rgba.length === 3 || (a >= 0 && a <= 1)
|
||||
|
||||
return isValidLengthRange && isValidColorRange && isValidAlphaRange
|
||||
}
|
||||
|
||||
//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 => v.toFixed(0))
|
||||
return hsvResult
|
||||
}
|
||||
|
||||
//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
|
||||
|
||||
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
|
||||
|
||||
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 [h, sl * 100, l * 100]
|
||||
}
|
Loading…
Reference in New Issue