@wilfredlopez/color-converter
TypeScript icon, indicating that this package has built-in type declarations

1.0.8 • Public • Published

ColorConverter

Get tints and shades of a CSS color and utility methods to work with colors in javascript.

Supports

  • [hexadecimal RGB/A notation]: #RGB #RRGGBB #RGBA #RRGGBBAA
  • [hex value] : 0xff0000
  • [RGB/A] - CSS Color Module Level 3 and 4 "rgba(255 500 0 / 25%)" "rgb(100% 0% 101% / 1)"
  • [HSL/A] - CSS Color Module Level 3 and 4 (number, deg, rad, turn) eg. "hsl(0, 100%, 50%)"
  • [pre-defined]: One of the pre-defined color keywords.
  • [transparent]: Shorthand for transparent black, rgba(0,0,0,0).

Install

NPM

npm install @wilfredlopez/color-converter --save

or

yarn add @wilfredlopez/color-converter

Or from a CDN as ColorConverter:

<head>
  <script src="https://unpkg.com/@wilfredlopez/color-converter"></script>
</head>
<body>
  <script>
    // The class is not the default export. in order to access the class you need to use this sintax
    const color = new ColorConverter.ColorConverter("#ffffff");
    console.log(color);
    //You can also access other methods like
    ColorConverter.parse("#ffffff"); // { alpha: 1, type: "rgb", values: (3) [255, 255, 255]}
    ColorConverter.convert.rgb.hex([255, 255, 255]); //"#ffffff"
    ColorConverter.hex2Rgb("#ffffff"); // {red: 255, green: 255, blue: 255, alpha: 1}
    ColorConverter.mix("red", "green"); // {hex: "#804000", hexa: "#804000ff", rgba: [128, 64, 0, 1], hsla:  [30, 100, 25, 1]}
  </script>
</body>

Usage

import {ColorConverter} from '@wilfredlopez/color-converter'
const color = new ColorConverter('hsl(204deg 100% 50% / 1)')

console.log(color.tint(25))
//> { rgb: [64, 179, 255], alpha: 1, type: "tint", weight: 25, ...methods }
console.log(color.shade(12))
//> { rgb: [0, 135, 224], alpha: 1, type: "shade", weight: 12, ...methods }
console.log(color.tints(8))
//> (12) [ColorConverter...]
console.log(color.shades(23))
//> (4) [ColorConverter...]
console.log(color.all(20))
//> (11) [ColorConverter...]

// example instance
ColorConverter {
  rgb: RGBType // [255, 0, 0]
  alpha: number
  type: ColorConverterType
  weight: number
  get hex() string //without the #
  get hexInverted(): string
  get hsl():string
  get hslObject(): HslObject
  get hsbObject(): HsbObject
  get rgbObject(): RgbObject
  get rgbaObject(): RgbaObject
  setColor: ƒ setColor(color)
  tint: ƒ tint(weight=50)
  tints: ƒ tints(weight=10)
  shade: ƒ shade(weight=50)
  shades: ƒ shades(weight=10)
  all: ƒ all(weight=10)
  hexString: ƒ hexString() // #ffffff
  rgbString: ƒ rgbString()
  hlsString: ƒ hlsString()
  getBrightness: ƒ getBrightness()
  getContrast: ƒ getContrast(threshold?: number)
  toRGBA(): RGBAType
  toColorObject(): ColorObject
}

Methods

constructor

Throws if the color is not accepted.

  • @param {string} color — a valid CSS color string (red, green, #fff, #000000)

  • @param {number} alpha - between 0 and 1. defaults to 1

  • @param {ColorConverterType} type - "shade" | "base" | "tint"

  • @param {number} weight - defaults to 0

constructor ColorConverter(color?: string | number, alpha?: number, type?: ColorConverterType, weight?: number): ColorConverter

setColor(color)

Sets a new base color, returns null if color has not been accepted.

  • @param {string} color - a valid CSS color string
  • @return {ColorConverter|null}

tint([weight=50])

Lightens the base color by mixing it with white as specified by weight.

  • @param {number} [weight=50]
  • @return {ColorConverter}

shade([weight=50)

Darkens the base color by mixing it with black as specified by weight.

  • @param {number} [weight=50]
  • @return {ColorConverter}

tints([weight=10])

Generates the tints of the base color as specified by weight.

  • @param {number} [weight=10]
  • @return {Array<ColorConverter>}

shades([percentage=10])

Generates the shades of the base color as specified by weight.

  • @param {number} [weight=10]
  • @return {Array<ColorConverter>}

all([weight=10])

Generates the tints and shades of the base color as specified by weight.

  • @param {number} [weight=10]
  • @return {Array<ColorConverter>}

hexString()

Returns the color in hexadecimal RGB notation.

  • @returns {string} @example #000000 or #00000080

rgbString()

Returns the color in rgb() functional notation.

  • @returns {string} @example rgb(0, 0, 0) or rgba(0, 0, 0, 0.5)

getBrightness()

Calculates the brightness of the color.

  • @return {number} — the base-color brightness.

Canvas Utililites (HTMLCanvasElement)

example with React

Component with Canvas

import React, { useRef, useMemo } from "react";
import {
  canvasUtils,
  ColorModels,
  ColorObject
} from "@wilfredlopez/color-converter";

const {
  getCoordinatesByHue,
  moveAt,
  getHueByCoordinates,
  changeHue
} = canvasUtils;

export interface SaturationProps {
  width: number;
  height: number;
  color: ColorObject;
  setColor: (color: ColorObject) => void;
}
// COMPONENT CONTAINING CANVAS
export const Saturation = ({
  width,
  height,
  color,
  setColor
}: SaturationProps) => {
  const paletteRef = useRef<HTMLCanvasElement>(null);

  const cursorPosition = useMemo(() => {
    const [x, y] = getCoordinatesByColor(color, width, height);

    return { x, y };
  }, [color, width, height]);

  useEffect(() => {
    const drawPalette = (): void => {
      if (paletteRef.current) {
        const ctx = paletteRef.current.getContext("2d");

        if (ctx) {
          const saturation = ctx.createLinearGradient(
            0,
            height / 2,
            width,
            height / 2
          );

          saturation.addColorStop(0, "white");
          saturation.addColorStop(1, `hsl(${color.hsb.hue}, 100%, 50%)`);

          ctx.fillStyle = saturation;
          ctx.fillRect(0, 0, width, height);

          const brightness = ctx.createLinearGradient(
            width / 2,
            0,
            width / 2,
            height
          );

          brightness.addColorStop(0, "transparent");
          brightness.addColorStop(1, "black");

          ctx.fillStyle = brightness;
          ctx.fillRect(0, 0, width, height);
        }
      }
    };

    if (paletteRef.current) drawPalette();
  }, [color.hsb.hue, width, height]);

  const moveCursor = (
    x: number,
    y: number,
    shiftX: number,
    shiftY: number
  ): void => {
    const [newX, newY] = moveAt(
      { value: x, shift: shiftX, min: 0, max: width },
      { value: y, shift: shiftY, min: 0, max: height }
    );

    const newColor = getColorByCoordinates(
      color.hsb.hue,
      newX,
      newY,
      width,
      height
    );

    setColor(newColor);
  };

  const onMouseDown = (e: React.MouseEvent): void => {
    if (paletteRef.current) {
      if (e.button !== 0) return;

      document.getSelection()?.empty();

      const {
        left: shiftX,
        top: shiftY
      } = paletteRef.current.getBoundingClientRect();

      moveCursor(e.clientX, e.clientY, shiftX, shiftY);

      const mouseMove = (e: MouseEvent): void => {
        moveCursor(e.clientX, e.clientY, shiftX, shiftY);
      };
      const mouseUp = (): void => {
        document.removeEventListener("mousemove", mouseMove, false);
        document.removeEventListener("mouseup", mouseUp, false);
      };

      document.addEventListener("mousemove", mouseMove, false);
      document.addEventListener("mouseup", mouseUp, false);
    }
  };

  return (
    <div className="saturation">
      <canvas
        ref={paletteRef}
        width={width}
        height={height}
        onMouseDown={onMouseDown}
      />
      <div
        className="saturation-cursor"
        style={{
          left: cursorPosition.x,
          top: cursorPosition.y,
          backgroundColor: color.hex
        }}
      />
    </div>
  );
};

BAR FOR SELECTING COLOR HUE

export interface HueBarProps {
  width: number;
  color: ColorObject;
  setColor: (color: ColorObject) => void;
}
// BAR FOR SELECTING COLOR HUE
export const HueBar = ({
  width,
  color,
  setColor
}: HueBarProps): JSX.Element => {
  const hueBarRef = useRef<HTMLDivElement>(null);

  const cursorPosition = useMemo(() => {
    const x = getCoordinatesByHue(color.hsb.hue, width);

    return x;
  }, [color.hsb.hue, width]);

  const moveCursor = (x: number, shiftX: number): void => {
    const [newX] = moveAt({
      value: x,
      shift: shiftX,
      min: 0,
      max: width
    });

    const newHue = getHueByCoordinates(newX, width);

    setColor(changeHue(color, newHue));
  };

  const onMouseDown = (e: React.MouseEvent): void => {
    if (hueBarRef.current) {
      if (e.button !== 0) return;

      document.getSelection()?.empty();

      const { left: shiftX } = hueBarRef.current.getBoundingClientRect();

      moveCursor(e.clientX, shiftX);

      const mouseMove = (e: MouseEvent): void => {
        moveCursor(e.clientX, shiftX);
      };
      const mouseUp = (): void => {
        document.removeEventListener("mousemove", mouseMove, false);
        document.removeEventListener("mouseup", mouseUp, false);
      };

      document.addEventListener("mousemove", mouseMove, false);
      document.addEventListener("mouseup", mouseUp, false);
    }
  };

  return (
    <div
      className="hue-bar"
      ref={hueBarRef}
      style={{
        width: width
      }}
      onMouseDown={onMouseDown}
    >
      <div
        className="hue-bar-cursor"
        style={{
          left: cursorPosition,
          backgroundColor: `hsl(${color.hsb.hue}, 100%, 50%)`
        }}
      />
    </div>
  );
};

Main Component

export interface ColorPickerProps {
  /**
   * The width of the color picker.
   */
  width: number;
  /**
   * The height of the color picker.
   */
  height?: number;
  /**
   * Color in the `ColorObject`.
   */
  color: ColorObject;
  /**
   * The function that accepts the updated `ColorObject` as a single argument.
   */
  onChange: (color: ColorObject) => void;
}

export interface ColorPickerBodyProps {
  width: number;
}

//Main Component
export const ColorPicker = ({
  width,
  height = width,
  color,
  onChange
}: ColorPickerProps): JSX.Element => (
  <div className="color-picker">
    <Saturation
      width={width}
      height={height}
      color={color}
      setColor={onChange}
    />
    <div
      className="color-picker-body"
      style={{
        width: width + "px"
      }}
    >
      <HueBar width={width - 5} color={color} setColor={onChange} />
    </div>
  </div>
);

APP Component

import React, { useState, useEffect } from "react";
import { ColorConverter, ColorObject } from "@wilfredlopez/color-converter";
import { ColorPicker } from "./components/ColorPicker";

const DEFAULT_STYLE: React.CSSProperties = {
  width: 90,
  height: 80,
  textAlign: "center",
  justifyContent: "center",
  display: "flex",
  flexDirection: "column"
};

export function App() {
  const [color, setColor] = useState<ColorObject>({
    hex: "#a71f71",
    hsb: {
      hue: 323.8235294117647,
      saturation: 81.437125748503,
      brightness: 65.49019607843137
    },
    rgb: { red: 167, blue: 113, green: 31 }
  });
  const [converColor, setConvertColors] = useState(
    new ColorConverter(color.hex)
  );

  useEffect(() => {
    setConvertColors(new ColorConverter(color.hex));
  }, [color]);

  return (
    <div className="container">
      <ColorPicker
        width={400}
        color={color}
        height={250}
        onChange={e => {
          setColor(e);
        }}
      />

      <div
        style={{
          ...DEFAULT_STYLE,
          border: "1px solid",
          background: color.hex,
          color: converColor.getContrast().hexString()
        }}
      >
        {color.hex}
      </div>

      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr 1fr",
          gridGap: "1px"
        }}
      >
        {converColor.all().map(c => {
          return (
            <div
              style={{
                ...DEFAULT_STYLE,
                background: c.hexString(),
                color: c.getContrast().hexString()
              }}
            >
              {c.hexString()}
            </div>
          );
        })}
      </div>
    </div>
  );
}

Package Sidebar

Install

npm i @wilfredlopez/color-converter

Weekly Downloads

1

Version

1.0.8

License

MIT

Unpacked Size

217 kB

Total Files

57

Last publish

Collaborators

  • wilfredlopez