react-color-selector
Version:
## **Description:** **react-color-selector** is a very useful and easy to use color picker, no external dependency is needed for this. You can chagne theme of it's color, by simply editing css variables. One of the best featur is you can use *any number
383 lines (338 loc) • 12.3 kB
JavaScript
import React, { useState, useRef, useEffect } from 'react';
import './ColorSelector.css'
const ColorSelector = (props) => {
let [pcolor, setColor] = useState('#ffffff');
let [colorString, setColorString] = useState(pcolor.substring(1));
const sqrCanvas = useRef(null);
let [sq_canvas, set_sq_canvas] = useState();
let [sq_context, set_sq_context] = useState();
let [cw, set_cw] = useState(0);
let [ch, set_ch] = useState(0);
let [colorCells, set_colorCells] = useState([]);
let [mouseX, setMouseX] = useState(0);
let [mouseY, setMouseY] = useState(0);
let [indicator_data, set_indicator_data] = useState({
w: 0,
h: 0,
t: 0,
l: 0
})
let usersPallet = props.pallet.view;
let [palletType, setPalletType] = useState(props.pallet.view);
let [p_col, set_p_col] = useState(props.pallet.col)
let [p_rows, set_p_rows] = useState(props.pallet.row)
useEffect(() => {
set_sq_canvas(sq_canvas = sqrCanvas.current);
set_sq_context(sq_context = sq_canvas.getContext('2d'));
// create_cells();
setUp(palletType);
// ------------------- clean up function --------------------
return function cleanup() {
sq_canvas.removeEventListener("click", pickColor, false);
}
}, []);
const HSLToHex = (h, s, l) => {
s /= 100;
l /= 100;
let c = (1 - Math.abs(2 * l - 1)) * s,
x = c * (1 - Math.abs((h / 60) % 2 - 1)),
m = l - c / 2,
r = 0,
g = 0,
b = 0;
if (0 <= h && h < 60) {
r = c; g = x; b = 0;
} else if (60 <= h && h < 120) {
r = x; g = c; b = 0;
} else if (120 <= h && h < 180) {
r = 0; g = c; b = x;
} else if (180 <= h && h < 240) {
r = 0; g = x; b = c;
} else if (240 <= h && h < 300) {
r = x; g = 0; b = c;
} else if (300 <= h && h < 360) {
r = c; g = 0; b = x;
}
// Having obtained RGB, convert channels to hex
r = Math.round((r + m) * 255).toString(16);
g = Math.round((g + m) * 255).toString(16);
b = Math.round((b + m) * 255).toString(16);
// Prepend 0s, if necessary
if (r.length == 1)
r = "0" + r;
if (g.length == 1)
g = "0" + g;
if (b.length == 1)
b = "0" + b;
return "#" + r + g + b;
}
const RGBToHex = (r, g, b) => {
r = r.toString(16);
g = g.toString(16);
b = b.toString(16);
if (r.length == 1)
r = "0" + r;
if (g.length == 1)
g = "0" + g;
if (b.length == 1)
b = "0" + b;
return "#" + r + g + b;
}
const getColor = (row, col) => {
const hue = Math.floor(row / p_rows * 360);
const sat = 100;
const lit = Math.floor((1 - (col + 1) / (p_col + 1)) * 100);
return HSLToHex(hue, sat, lit);
}
function Cell(i, j, ctx, color, unit_x, unit_y) {
this.color = color;
this.x = i * unit_x;
this.y = j * unit_y;
this.unit_x = unit_x;
this.unit_y = unit_y;
this.show = () => {
ctx.beginPath();
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y + this.unit_y, this.unit_x, this.unit_y);
if (this.y === 0) {
let color_unit = parseInt(255 - ((255 / p_col) * i));
ctx.fillStyle = `rgb(${color_unit}, ${color_unit}, ${color_unit})`;
ctx.fillRect(this.x, this.y, this.unit_x, this.unit_y);
// this.color = `rgb(${color_unit}, ${color_unit}, ${color_unit})`;
}
}
this.clicked = (mouseX, mouseY) => {
if (mouseX >= this.x && mouseX <= this.x + this.unit_x && mouseY >= this.y + this.unit_y && mouseY <= this.y + 2 * this.unit_y) {
let retrun_obj = {
color: this.color,
gs: false
}
return retrun_obj;
}
if (mouseX >= this.x && mouseX <= this.x + this.unit_x && mouseY >= 0 && mouseY <= this.unit_y) {
let color_unit = parseInt(255 - ((255 / p_col) * i));
// return `rgb(${color_unit}, ${color_unit}, ${color_unit})`;
let retrun_obj = {
color: RGBToHex(color_unit, color_unit, color_unit),
gs: true
}
return retrun_obj;
}
}
this.hover = (mouseX, mouseY) => {
if (mouseX >= this.x && mouseX <= this.x + this.unit_x && mouseY >= this.y + this.unit_y && mouseY <= this.y + this.unit_y) {
ctx.lineWidth = '0.5';
ctx.strokeStyle = `#ffffff`;
ctx.strokeRect(this.x, this.y, this.unit_x, this.unit_y);
}
}
}
const create_cells = () => {
if (palletType === 'palette' || palletType === 'both') {
set_colorCells(colorCells = []);
let local_cells = [];
let init_unit_y = (sq_canvas.height / p_rows);
let unit_x = (sq_canvas.width / p_col);
// let unit_y = ((sq_canvas.height - init_unit_y) / p_rows);
let unit_y = (sq_canvas.height / p_rows);
for (let j = 0; j < p_rows; j++) {
for (let i = 0; i < p_col; i++) {
var cell = new Cell(i, j, sq_context, getColor(i, j), unit_x, unit_y)
local_cells.push(cell);
}
}
// ------------------ drawin cells ----------------------
local_cells.map((c) => { c.show() }); // main canvas cells
set_colorCells(colorCells = local_cells);
} else {
var cx = sq_canvas.width / 2,
cy = sq_canvas.height / 2,
sx = cx,
sy = cy;
for (var i = 0; i < 360; i += 0.1) {
var rad = i * (2 * Math.PI) / 360;
sq_context.strokeStyle = "hsla(" + i + ", 100%, 50%, 1.0)";
sq_context.beginPath();
sq_context.moveTo(cx, cy);
sq_context.lineTo(cx + sx * Math.cos(rad), cy + sy * Math.sin(rad));
sq_context.stroke();
}
}
}
const setUp = (view) => {
if (view === 'both') {
setPalletType(palletType = 'palette');
} else {
setPalletType(palletType = view);
}
if (palletType === 'palette' || palletType === 'both') {
sq_canvas.width = props.pallet.width;
sq_canvas.height = props.pallet.height;
set_cw(cw = props.pallet.width);
set_ch(ch = props.pallet.height);
} else {
if (props.pallet.height < props.pallet.width) {
sq_canvas.width = props.pallet.height;
sq_canvas.height = props.pallet.height;
set_cw(cw = props.pallet.height + 30);
set_ch(ch = props.pallet.height + 30);
} else {
sq_canvas.width = props.pallet.width;
sq_canvas.height = props.pallet.width;
set_cw(cw = props.pallet.width + 30);
set_ch(ch = props.pallet.width + 30);
}
}
sq_canvas.addEventListener("click", pickColor, false);
create_cells();
}
const pickColor = (e) => {
mouse_pos(e);
if (palletType === 'palette' || palletType === 'both') {
let pickedColor;
let cellObject;
for (let i = 0; i < colorCells.length; i++) {
pickedColor = colorCells[i].clicked(mouseX, mouseY);
if (pickedColor) {
cellObject = colorCells[i]
break;
}
}
setColor(pcolor = pickedColor.color);
setColorString(colorString = pickedColor.color.substring(1));
let ty;
if (pickedColor.gs === false) {
ty = cellObject.y + cellObject.unit_y;
} else {
ty = cellObject.y;
}
set_indicator_data(indicator_data = { w: cellObject.unit_x, h: cellObject.unit_y, t: ty, l: cellObject.x })
} else {
console.log('sphere');
let pixelData = sq_context.getImageData(mouseX, mouseY, 1, 1).data;
var hex = "#" + ("000000" + RGBToHex(pixelData[0], pixelData[1], pixelData[2])).slice(-6);
setColor(pcolor = hex);
setColorString(colorString = hex.substring(1));
}
props.selectedColor(pcolor);
}
/**
*
* @param {*} e : This provides the mouse position on main canvas
* adding scrlLeft and scrlTop values so that after moving
* horizontal or vertical it gets the task's x and y
*/
const mouse_pos = (e) => {
var element = sq_canvas;
var offsetX = 0, offsetY = 0;
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
setMouseX(mouseX = (e.pageX - offsetX));
setMouseY(mouseY = (e.pageY - offsetY));
}
const increseCols = () => {
set_p_col(p_col = p_col + props.pallet.cellControl)
set_p_rows(p_rows = p_rows + props.pallet.cellControl)
console.log('p_col ', p_col, 'p_rows', p_rows)
setUp(palletType);
}
const decreseCols = () => {
console.log('p_col ', p_col);
if (p_col > props.pallet.col) {
set_p_col(p_col = p_col - props.pallet.cellControl)
set_p_rows(p_rows = p_rows - props.pallet.cellControl)
console.log('p_col ', p_col, 'p_rows', p_rows)
setUp(palletType);
}
}
return (
<React.Fragment>
<div className={`${props.pallet.theme === 'dark' ? 'dark-theme' : 'light-theme'}`} style={{ width: (cw + 30) + 'px', height: (ch + 140) + 'px' }}>
<ul className={`picker_switch`}>
<li>{props.pallet.title}</li>
<li style={{ textAlign: 'center' }}>
{palletType === 'palette' && props.pallet.cellControl &&
<div>
<button type="button" className="tools" onClick={() => decreseCols()}>-</button>
<button type="button" className="tools" onClick={() => increseCols()}>+</button>
</div>
}
</li>
<li style={{ textAlign: 'right' }}>
{usersPallet === 'both' &&
<div>
<button type="button" className={`picker-btn s_pallet ${palletType === 'palette' || palletType === 'both' ? 'active' : ''}`} onClick={() => setUp('palette')}>
<span></span>
<span></span>
<span></span>
<span></span>
</button>
<button type="button" className={`picker-btn s_sphear ${palletType === 'sphere' ? 'active' : ''}`} onClick={() => setUp('sphere')}>
<span></span>
</button>
</div>
}
</li>
</ul>
<div className={`canvas_holder ${palletType === 'sphere' ? 'sphere_holder' : ''}`} style={{ width: palletType === 'sphere' ? cw - 30 : cw + 'px', height: palletType === 'sphere' ? ch - 30 : ch + 'px', borderColor: pcolor + 'aa' }}>
<canvas className="sqr_canvas picker_area" ref={sqrCanvas} style={{ borderRadius: '6px' }} />
{palletType}
{(palletType === 'palette' || palletType === 'both') &&
<div className={`indicator `} style={{ width: indicator_data.w + 'px', height: indicator_data.h + 'px', top: indicator_data.t + 'px', left: indicator_data.l + 'px' }}></div>
}
{palletType === 'sphere' &&
<div className={`indicator with_sphere`} style={{ top: mouseY + 'px', left: mouseX + 'px' }}></div>
}
</div>
<div className={`result_bar`}>
<div className={`unit_section`}>#</div>
<input className={`output_input`} type="text" value={colorString} onChange={(e) => { setColorString(colorString = e.target.value); setColor(pcolor = '#' + e.target.value); props.selectedColor('#' + e.target.value); }} />
<div className={`result_output `} style={{ backgroundColor: pcolor }}></div>
</div>
</div>
</React.Fragment>
);
}
export default ColorSelector;
/**
*
* function HSLToHex(h,s,l) {
s /= 100;
l /= 100;
let c = (1 - Math.abs(2 * l - 1)) * s,
x = c * (1 - Math.abs((h / 60) % 2 - 1)),
m = l - c/2,
r = 0,
g = 0,
b = 0;
if (0 <= h && h < 60) {
r = c; g = x; b = 0;
} else if (60 <= h && h < 120) {
r = x; g = c; b = 0;
} else if (120 <= h && h < 180) {
r = 0; g = c; b = x;
} else if (180 <= h && h < 240) {
r = 0; g = x; b = c;
} else if (240 <= h && h < 300) {
r = x; g = 0; b = c;
} else if (300 <= h && h < 360) {
r = c; g = 0; b = x;
}
// Having obtained RGB, convert channels to hex
r = Math.round((r + m) * 255).toString(16);
g = Math.round((g + m) * 255).toString(16);
b = Math.round((b + m) * 255).toString(16);
// Prepend 0s, if necessary
if (r.length == 1)
r = "0" + r;
if (g.length == 1)
g = "0" + g;
if (b.length == 1)
b = "0" + b;
return "#" + r + g + b;
}
*/