色文字列からRGBA値を取得できる「Gnjo JS」を使ってもっと"色"と仲良くなろう
Gnjo JS とは
例えば
import * as Gnjo from 'gnjo'
const [rgba, errors] = Gnjo.parse("#0074de")
console.log(rgba.r) // 0
console.log(rgba.g) // 116
console.log(rgba.b) // 255
console.log(rgba.alpha) // 1.0
みたいに、CSSで使える色文字列をパースしてJS/TSから使いやすいオブジェクトを取得したり...
// CIE L*a*b 色空間
const lab = new Gnjo.LabSpace(68, 38, -49)
const rgb = lab.toRGBA()
const rgbStr = rgb.toString() // rgb(187, 145, 255)
のようにRGB, HSL, HWBに加え、通常CSSからは使えないCIE XYZ色空間やCIE Lab色空間を相互に変換、描画可能な文字列を取得するなどができたり...
const color = new Gnjo.RGBASpace(255, 255, 255)
// その色の明度は(視覚的に)明るいか
const isLight = Gnjo.isLight(color)
// 補色を取得
const complementaryColor = Gnjo.getComplemetaryColor(color)
const backgroundColor = new Gnjo.RGBASpace(0, 0, 0)
// WCAG 2.0において、2つの色が視覚的に十分判別可能かどうかテストする
const [AAPassed, AAAPassed] = Gnjo.testContrastRatio(color, backgroundColor, "text")
このようなユーティリティ関数を提供したりしています。
インストール
Gnjo JSはnpmに公開しているため、npm/Yarnでインストールできます。
npm install gnjo
# ...or
yarn add gnjo
TypeScriptの型情報も同時に提供しており、型安全に利用できるライブラリです。
仕組み
文字列をパースして色空間クラスのインスタンスを取得していた関数 Gnjo.parse
の中身から分かるとおり...
const lexer = new Gnjo.Lexer("rgba(255, 255, 255, 1)");
const parser = new Gnjo.Parser(lexer);
const [ast, errors] = parser.parse();
if (errors.length > 0) { /* handle errors */ }
if (ast === null) {/* when ast is null */ }
const evaluator = new Gnjo.Evaluator(ast!)
const colorSpace = evaluator.evaluate()
Gnjo JSはシンプルな字句解析器、構文解析器と評価器を持っています。
Lexer
は文字列を受け取り、文字列をトークンと呼ばれる解析する上で有意な最小単位に分解し、Parser
はトークン列をAST(抽象構文木)と呼ばれる「意味」を持つ構造に変換し、Evaluator
がASTを評価し、ColorSpace
interfaceを実装したクラスのインスタンスへ変換します。
そこまでやる必要あった?
コンパイラなどと比べるとささやかな能力しか持たない解析機能ではあるものの、ぶっちゃけこんなレベルのものを用意せず、正規表現を活用する単純な設計でも良かったと思っています。
まあ良いんです。 柔軟に機能拡張できるロマンが詰まってますから。ロマンは創作の原動力です。
なんで作ったの?
僕が籍を置く会社で、僕主導でそこそこ重厚長大なデザインシステムを構築しており、下記の要件がその中にありました。
-
#FFFFFF
(背景色)に対しWCAG2.0で求められる基準を満たすコントラスト比を確保したカラーパレットを作成する。 - 1の条件を満たしつつ、CIE Lab色空間に基づいて、人間の視覚的に均質なカラーパレットを作成する。
- Lab色空間はそのままCSSでは使えないので、RGBなど使える文字列に変換する。
- コンポーネントの背景色の明度を判定し、文字色を自動で黒or白で描画する。
- JavaScriptインスタンスを
new
で作成するだけでなく、CSSで使える文字列をパースしてインスタンスを得る、という導線がある。
これらを同時に実現するとなると、もうライブラリ自作しかなかったので作りました。最近「無ければ俺が作ればいい」というスタンスを大事にしようと思っていたのでちょうどいいお題でもありました。
僕は色彩に関しては素人で、色空間の勉強やWCAGコントラスト基準など詳細に調べる必要があった部分も多かったため、プログラミング以外の領域の知識を深められたのも良かったです。
おわりに
僕にとって初めてのnpmプロジェクトで、初めてちゃんとOSSとして提供したライブラリでした。
README.mdは誤記や英語の文法誤りがあったり、テストケースの網羅率が高いとは言えなかったりと拙い部分が多い未熟なライブラリです。
ぜひ皆にプルリクやissueを投げて育てていただきたいと思っています。
Discussion