Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

color-octree

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

color-octree - npm Package Compare versions

Comparing version 2.0.2 to 2.1.0

.travis.yml

71

dist/cjs.js

@@ -79,8 +79,3 @@ 'use strict';

const hexToRgb = hex => {
const h = parseHex(hex);
return Array.from({
length: 3
}, (_, i) => parseInt(h.slice(2 * i, 2 * i + 2), 16));
};
const hexToRgb = hex => [parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16)];

@@ -107,12 +102,21 @@ const distRgb = (c1, c2) => (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) ** 2;

};
/**
* init __root
* @param {*} depth
*/
let root;
const init = () => {
root = buildOctree(7); // 8 would go down to leaves, but it's too intense for nodejs
const init = (depth = 7) => {
if (!(depth >= 0 && depth < 8)) throw new Error('depth must be between 0 and 7'); // 8 would go down to leaves, but it's too intense for nodejs
exports.__root = {};
exports.__root = _objectSpread({}, buildOctree(depth), {
depth,
colors: undefined
}); // colors are not stored at top-level
};
const add = cols => {
if (!root) init();
const add = (cols, depth) => {
if (!exports.__root) init(depth);
if (Array.isArray(cols)) {
return cols.forEach(c => _add(c)); // might want to precmpute rgb to spped up search
return cols.forEach(c => _add(c)); // might want to precompute rgb to speed up search
}

@@ -124,6 +128,6 @@

const _add = col => {
let node = root;
const bin = hexToBin(col.hex);
let node = exports.__root;
const bin = hexToBin(parseHex(col.hex));
for (let i = 0; i < 7; i++) {
for (let i = 0; i < exports.__root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];

@@ -134,2 +138,17 @@ node = node[k];

};
const remove = hex => {
let node = exports.__root;
const bin = hexToBin(parseHex(hex));
for (let i = 0; i < exports.__root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];
node = node[k];
const idx = node.colors.findIndex(c => c.hex === hex);
if (idx >= 0) {
node.colors = [...node.colors.slice(0, idx), ...node.colors.slice(idx + 1)]; // don't like splice
}
}
};
/**

@@ -140,3 +159,2 @@ * get neighbors of a given node

const neighbors = ([r, g, b], dir) => {

@@ -166,6 +184,14 @@ const rDec = parseInt(r, 2);

const getNodeFromCoords = ([r, g, b]) => [...r].reduce((node, ri, i) => node[ri + g[i] + b[i]], root);
const getNodeFromCoords = ([r, g, b]) => {
let node = exports.__root;
for (let i = 0; i < Math.min(exports.__root.depth, r.length); i++) {
node = node[r[i] + g[i] + b[i]];
}
return node;
};
const closest = hex => {
const rgb = hexToRgb(hex);
const rgb = hexToRgb(parseHex(hex));

@@ -179,7 +205,7 @@ const _rgbToBin = rgbToBin(rgb),

for (let i = 7; i > 0; i--) {
for (let i = exports.__root.depth; i > 0; i--) {
const coords = [r.slice(0, i), g.slice(0, i), b.slice(0, i)]; // take one resolution higher, since we don't/can't store level 8
const ns = neighbors(coords, r[i] + g[i] + b[i]);
const colors = ns.reduce((cs, n) => cs.concat(getNodeFromCoords(n).colors), []);
const colors = ns.map(n => getNodeFromCoords(n).colors).reduce((cs, c) => cs.concat(c), []);

@@ -192,3 +218,3 @@ if (colors.length) {

const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].reduce((cs, c) => cs.concat(root[c].colors), []);
const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].map(node => exports.__root[node].colors).reduce((cs, c) => cs.concat(c), []);

@@ -206,3 +232,3 @@ if (colors.length) {

colors.forEach(col => {
const d = distRgb(hexToRgb(col.hex), rgb);
const d = distRgb(hexToRgb(parseHex(col.hex)), rgb);

@@ -224,2 +250,3 @@ if (d < minDist) {

exports.add = add;
exports.remove = remove;
exports.closest = closest;

@@ -75,8 +75,3 @@ function _defineProperty(obj, key, value) {

const hexToRgb = hex => {
const h = parseHex(hex);
return Array.from({
length: 3
}, (_, i) => parseInt(h.slice(2 * i, 2 * i + 2), 16));
};
const hexToRgb = hex => [parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16)];

@@ -104,11 +99,22 @@ const distRgb = (c1, c2) => (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) ** 2;

let root;
const init = () => {
root = buildOctree(7); // 8 would go down to leaves, but it's too intense for nodejs
let __root;
/**
* init __root
* @param {*} depth
*/
const init = (depth = 7) => {
if (!(depth >= 0 && depth < 8)) throw new Error('depth must be between 0 and 7'); // 8 would go down to leaves, but it's too intense for nodejs
__root = {};
__root = _objectSpread({}, buildOctree(depth), {
depth,
colors: undefined
}); // colors are not stored at top-level
};
const add = cols => {
if (!root) init();
const add = (cols, depth) => {
if (!__root) init(depth);
if (Array.isArray(cols)) {
return cols.forEach(c => _add(c)); // might want to precmpute rgb to spped up search
return cols.forEach(c => _add(c)); // might want to precompute rgb to speed up search
}

@@ -120,6 +126,6 @@

const _add = col => {
let node = root;
const bin = hexToBin(col.hex);
let node = __root;
const bin = hexToBin(parseHex(col.hex));
for (let i = 0; i < 7; i++) {
for (let i = 0; i < __root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];

@@ -130,2 +136,17 @@ node = node[k];

};
const remove = hex => {
let node = __root;
const bin = hexToBin(parseHex(hex));
for (let i = 0; i < __root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];
node = node[k];
const idx = node.colors.findIndex(c => c.hex === hex);
if (idx >= 0) {
node.colors = [...node.colors.slice(0, idx), ...node.colors.slice(idx + 1)]; // don't like splice
}
}
};
/**

@@ -136,3 +157,2 @@ * get neighbors of a given node

const neighbors = ([r, g, b], dir) => {

@@ -162,6 +182,14 @@ const rDec = parseInt(r, 2);

const getNodeFromCoords = ([r, g, b]) => [...r].reduce((node, ri, i) => node[ri + g[i] + b[i]], root);
const getNodeFromCoords = ([r, g, b]) => {
let node = __root;
for (let i = 0; i < Math.min(__root.depth, r.length); i++) {
node = node[r[i] + g[i] + b[i]];
}
return node;
};
const closest = hex => {
const rgb = hexToRgb(hex);
const rgb = hexToRgb(parseHex(hex));

@@ -175,7 +203,7 @@ const _rgbToBin = rgbToBin(rgb),

for (let i = 7; i > 0; i--) {
for (let i = __root.depth; i > 0; i--) {
const coords = [r.slice(0, i), g.slice(0, i), b.slice(0, i)]; // take one resolution higher, since we don't/can't store level 8
const ns = neighbors(coords, r[i] + g[i] + b[i]);
const colors = ns.reduce((cs, n) => cs.concat(getNodeFromCoords(n).colors), []);
const colors = ns.map(n => getNodeFromCoords(n).colors).reduce((cs, c) => cs.concat(c), []);

@@ -188,3 +216,3 @@ if (colors.length) {

const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].reduce((cs, c) => cs.concat(root[c].colors), []);
const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].map(node => __root[node].colors).reduce((cs, c) => cs.concat(c), []);

@@ -202,3 +230,3 @@ if (colors.length) {

colors.forEach(col => {
const d = distRgb(hexToRgb(col.hex), rgb);
const d = distRgb(hexToRgb(parseHex(col.hex)), rgb);

@@ -215,2 +243,2 @@ if (d < minDist) {

export { parseHex, distHex, hexToBin, init, add, closest };
export { parseHex, distHex, hexToBin, __root, init, add, remove, closest };

@@ -81,8 +81,3 @@ (function (global, factory) {

const hexToRgb = hex => {
const h = parseHex(hex);
return Array.from({
length: 3
}, (_, i) => parseInt(h.slice(2 * i, 2 * i + 2), 16));
};
const hexToRgb = hex => [parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16)];

@@ -109,12 +104,21 @@ const distRgb = (c1, c2) => (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) ** 2;

};
/**
* init __root
* @param {*} depth
*/
let root;
const init = () => {
root = buildOctree(7); // 8 would go down to leaves, but it's too intense for nodejs
const init = (depth = 7) => {
if (!(depth >= 0 && depth < 8)) throw new Error('depth must be between 0 and 7'); // 8 would go down to leaves, but it's too intense for nodejs
exports.__root = {};
exports.__root = _objectSpread({}, buildOctree(depth), {
depth,
colors: undefined
}); // colors are not stored at top-level
};
const add = cols => {
if (!root) init();
const add = (cols, depth) => {
if (!exports.__root) init(depth);
if (Array.isArray(cols)) {
return cols.forEach(c => _add(c)); // might want to precmpute rgb to spped up search
return cols.forEach(c => _add(c)); // might want to precompute rgb to speed up search
}

@@ -126,6 +130,6 @@

const _add = col => {
let node = root;
const bin = hexToBin(col.hex);
let node = exports.__root;
const bin = hexToBin(parseHex(col.hex));
for (let i = 0; i < 7; i++) {
for (let i = 0; i < exports.__root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];

@@ -136,2 +140,17 @@ node = node[k];

};
const remove = hex => {
let node = exports.__root;
const bin = hexToBin(parseHex(hex));
for (let i = 0; i < exports.__root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];
node = node[k];
const idx = node.colors.findIndex(c => c.hex === hex);
if (idx >= 0) {
node.colors = [...node.colors.slice(0, idx), ...node.colors.slice(idx + 1)]; // don't like splice
}
}
};
/**

@@ -142,3 +161,2 @@ * get neighbors of a given node

const neighbors = ([r, g, b], dir) => {

@@ -168,6 +186,14 @@ const rDec = parseInt(r, 2);

const getNodeFromCoords = ([r, g, b]) => [...r].reduce((node, ri, i) => node[ri + g[i] + b[i]], root);
const getNodeFromCoords = ([r, g, b]) => {
let node = exports.__root;
for (let i = 0; i < Math.min(exports.__root.depth, r.length); i++) {
node = node[r[i] + g[i] + b[i]];
}
return node;
};
const closest = hex => {
const rgb = hexToRgb(hex);
const rgb = hexToRgb(parseHex(hex));

@@ -181,7 +207,7 @@ const _rgbToBin = rgbToBin(rgb),

for (let i = 7; i > 0; i--) {
for (let i = exports.__root.depth; i > 0; i--) {
const coords = [r.slice(0, i), g.slice(0, i), b.slice(0, i)]; // take one resolution higher, since we don't/can't store level 8
const ns = neighbors(coords, r[i] + g[i] + b[i]);
const colors = ns.reduce((cs, n) => cs.concat(getNodeFromCoords(n).colors), []);
const colors = ns.map(n => getNodeFromCoords(n).colors).reduce((cs, c) => cs.concat(c), []);

@@ -194,3 +220,3 @@ if (colors.length) {

const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].reduce((cs, c) => cs.concat(root[c].colors), []);
const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].map(node => exports.__root[node].colors).reduce((cs, c) => cs.concat(c), []);

@@ -208,3 +234,3 @@ if (colors.length) {

colors.forEach(col => {
const d = distRgb(hexToRgb(col.hex), rgb);
const d = distRgb(hexToRgb(parseHex(col.hex)), rgb);

@@ -226,2 +252,3 @@ if (d < minDist) {

exports.add = add;
exports.remove = remove;
exports.closest = closest;

@@ -228,0 +255,0 @@

@@ -6,6 +6,8 @@ export const parseHex = hex =>

const hexToRgb = hex => {
const h = parseHex(hex);
return Array.from({ length: 3 }, (_, i) => parseInt(h.slice(2 * i, 2 * i + 2), 16));
};
const hexToRgb = hex => [
parseInt(hex.slice(0, 2), 16),
parseInt(hex.slice(2, 4), 16),
parseInt(hex.slice(4, 6), 16)
];
const distRgb = (c1, c2) => (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) ** 2;

@@ -35,12 +37,19 @@

let root;
export let __root;
export const init = () => {
root = buildOctree(7); // 8 would go down to leaves, but it's too intense for nodejs
/**
* init __root
* @param {*} depth
*/
export const init = (depth = 7) => {
if (!(depth >= 0 && depth < 8)) throw new Error('depth must be between 0 and 7');
// 8 would go down to leaves, but it's too intense for nodejs
__root = {};
__root = {...buildOctree(depth), depth, colors: undefined}; // colors are not stored at top-level
};
export const add = cols => {
if (!root) init();
export const add = (cols, depth) => {
if (!__root) init(depth);
if (Array.isArray(cols)) {
return cols.forEach(c => _add(c)); // might want to precmpute rgb to spped up search
return cols.forEach(c => _add(c)); // might want to precompute rgb to speed up search
}

@@ -51,5 +60,5 @@ _add(cols);

const _add = col => {
let node = root;
const bin = hexToBin(col.hex);
for (let i = 0; i < 7; i++) {
let node = __root;
const bin = hexToBin(parseHex(col.hex));
for (let i = 0; i < __root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];

@@ -61,2 +70,15 @@ node = node[k];

export const remove = hex => {
let node = __root;
const bin = hexToBin(parseHex(hex));
for (let i = 0; i < __root.depth; i++) {
const k = bin[0][i] + bin[1][i] + bin[2][i];
node = node[k];
const idx = node.colors.findIndex(c => c.hex === hex);
if (idx >= 0) {
node.colors = [...node.colors.slice(0,idx), ...node.colors.slice(idx+1)]; // don't like splice
}
}
}
/**

@@ -91,12 +113,18 @@ * get neighbors of a given node

const getNodeFromCoords = ([r, g, b]) => [...r].reduce((node, ri, i) => node[ri + g[i] + b[i]], root);
const getNodeFromCoords = ([r, g, b]) => {
let node = __root;
for (let i = 0; i < Math.min(__root.depth, r.length); i++) {
node = node[r[i] + g[i] + b[i]];
}
return node;
};
export const closest = hex => {
const rgb = hexToRgb(hex);
const rgb = hexToRgb(parseHex(hex));
const [r, g, b] = rgbToBin(rgb);
// reminder: we don't/can't store level 8
for (let i = 7; i > 0; i--) {
for (let i = __root.depth; i > 0; i--) {
const coords = [r.slice(0, i), g.slice(0, i), b.slice(0, i)]; // take one resolution higher, since we don't/can't store level 8
const ns = neighbors(coords, r[i] + g[i] + b[i]);
const colors = ns.reduce((cs, n) => cs.concat(getNodeFromCoords(n).colors), []);
const colors = ns.map(n => getNodeFromCoords(n).colors).reduce((cs, c) => cs.concat(c), []);
if (colors.length) {

@@ -107,6 +135,6 @@ return closestIn(rgb, colors);

// search in all
const colors = ['000', '001', '010', '011', '100', '101', '110', '111'].reduce(
(cs, c) => cs.concat(root[c].colors),
[],
);
const colors = ['000', '001', '010', '011', '100', '101', '110', '111']
.map(node => __root[node].colors)
.reduce((cs, c) => cs.concat(c), []);
if (colors.length) {

@@ -122,3 +150,3 @@ return closestIn(rgb, colors);

colors.forEach(col => {
const d = distRgb(hexToRgb(col.hex), rgb);
const d = distRgb(hexToRgb(parseHex(col.hex)), rgb);
if (d < minDist) {

@@ -125,0 +153,0 @@ minDist = d;

{
"name": "color-octree",
"version": "2.0.2",
"version": "2.1.0",
"description": "Get closest hex color",

@@ -9,4 +9,4 @@ "main": "dist/cjs.js",

"scripts": {
"test": "node test",
"prepare": "npx rollup -c"
"test": "babel-node index.spec",
"prepare": "NODE_ENV=rollup npx rollup -c"
},

@@ -32,2 +32,3 @@ "repository": {

"@babel/core": "^7.0.0-beta.44",
"@babel/node": "^7.0.0-beta.44",
"@babel/preset-env": "^7.0.0-beta.44",

@@ -34,0 +35,0 @@ "color-name-list": "^3.10.0",

## Find efficiently the closest hex color
### API
- `add(colors /*array of {hex, name}*/)`: add an array of colors (`add` calls `init` if it was not initialized yet)
- `closest(hex)`: Search for the closest color
- `init(depth: Int = 7)`: Init the tree at a given depth (default 7), accepted range: [0, 7]
- `remove(hex)`: Remove a a color object by its hex property
```js

@@ -15,1 +22,6 @@ import colorNames from 'color-names';

[live example](https://repl.it/@caub/closest-color)
### Notice
It uses `String.prototype.padStart`, it exist on node 8.11 and recent browsers, but you might still want to polyfill it (see polyfill.io or es-shims)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc