color-name-list 9.8.0 → 9.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -1
- package/scripts/findColors.js +40 -22
- package/scripts/generatePaletteName.js +48 -0
- package/scripts/server.js +59 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "color-name-list",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"description": "long list of color names",
|
|
5
5
|
"main": "dist/colornames.json",
|
|
6
6
|
"browser": "dist/colornames.umd.js",
|
|
@@ -33,10 +33,12 @@
|
|
|
33
33
|
"homepage": "https://github.com/meodai/color-names#readme",
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"closestvector": "^0.6.0",
|
|
36
|
+
"color-name-lists": "^1.1.0",
|
|
36
37
|
"commitizen": "^4.2.4",
|
|
37
38
|
"eslint": "^5.15.1",
|
|
38
39
|
"eslint-config-google": "^0.10.0",
|
|
39
40
|
"ghooks": "^2.0.4",
|
|
41
|
+
"seedrandom": "^3.0.5",
|
|
40
42
|
"semantic-release": "^17.4.2"
|
|
41
43
|
},
|
|
42
44
|
"engines": {
|
package/scripts/findColors.js
CHANGED
|
@@ -2,7 +2,7 @@ const lib = require('./lib.js');
|
|
|
2
2
|
const ClosestVector = require('closestvector');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* enriches color object and fills RGB color arrays
|
|
6
6
|
* Warning: Not a pure function at all :D
|
|
7
7
|
* @param {object} colorObj hex representation of color
|
|
8
8
|
* @param {array} rgbColorArrRef reference to RGB color array
|
|
@@ -24,24 +24,34 @@ const enrichColorObj = (colorObj, rgbColorArrRef) => {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
module.exports = class FindColors {
|
|
27
|
-
constructor(
|
|
28
|
-
|
|
29
|
-
this.colors = colors;
|
|
30
|
-
this.colorsBestOf = colorsBestOf;
|
|
27
|
+
constructor(colorsListsObj) {
|
|
28
|
+
this.colorLists = colorsListsObj;
|
|
31
29
|
|
|
32
30
|
// object containing the name:hex pairs for nearestColor()
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
31
|
+
this.colorListsRGBArrays = {};
|
|
32
|
+
this.closestInstances = {};
|
|
35
33
|
|
|
36
34
|
// prepare color array
|
|
37
|
-
this.
|
|
38
|
-
|
|
35
|
+
Object.keys(this.colorLists).forEach((listName) => {
|
|
36
|
+
this.colorListsRGBArrays[listName] = [];
|
|
37
|
+
|
|
38
|
+
this.colorLists[listName].forEach(c => {
|
|
39
|
+
enrichColorObj(c, this.colorListsRGBArrays[listName]);
|
|
40
|
+
});
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
Object.freeze(this.colorLists[listName]);
|
|
43
|
+
this.closestInstances[listName] = new ClosestVector(
|
|
44
|
+
this.colorListsRGBArrays[listName]
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
_validateListKey (listKey) {
|
|
50
|
+
if (!this.colorLists[listKey]) {
|
|
51
|
+
throw new Error(`List key "${listKey}" is not valid.`);
|
|
52
|
+
} else {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
/**
|
|
@@ -49,9 +59,11 @@ module.exports = class FindColors {
|
|
|
49
59
|
* @param {string} searchStr search term
|
|
50
60
|
* @param {boolen} bestOf if set only returns good names
|
|
51
61
|
*/
|
|
52
|
-
searchNames (searchStr,
|
|
53
|
-
|
|
54
|
-
return
|
|
62
|
+
searchNames (searchStr, listKey = 'default') {
|
|
63
|
+
this._validateListKey(listKey);
|
|
64
|
+
return this.colorLists[listKey].filter(
|
|
65
|
+
color => color.name.toLowerCase().includes(searchStr.toLowerCase())
|
|
66
|
+
);
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
/**
|
|
@@ -61,24 +73,30 @@ module.exports = class FindColors {
|
|
|
61
73
|
* @param {boolean} bestOf if set only returns good names
|
|
62
74
|
* @return {object} object containing all nearest colors
|
|
63
75
|
*/
|
|
64
|
-
getNamesForValues
|
|
65
|
-
let localClosest =
|
|
76
|
+
getNamesForValues(colorArr, unique = false, listKey = 'default') {
|
|
77
|
+
let localClosest = this.closestInstances[listKey];
|
|
66
78
|
|
|
67
79
|
if (unique) {
|
|
68
80
|
localClosest = new ClosestVector(
|
|
69
|
-
|
|
81
|
+
this.colorListsRGBArrays[listKey],
|
|
70
82
|
true
|
|
71
83
|
);
|
|
72
84
|
}
|
|
73
85
|
|
|
86
|
+
let lastResult = null;
|
|
87
|
+
|
|
74
88
|
const colorResp = colorArr.map((hex) => {
|
|
75
89
|
// calculate RGB values for passed color
|
|
76
90
|
const rgb = lib.hexToRgb(hex);
|
|
77
91
|
|
|
78
92
|
// get the closest named colors
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
let closestColor = localClosest.get([rgb.r, rgb.g, rgb.b]);
|
|
94
|
+
if (closestColor && unique) {
|
|
95
|
+
lastResult = closestColor;
|
|
96
|
+
} else if (unique) {
|
|
97
|
+
closestColor = lastResult;
|
|
98
|
+
}
|
|
99
|
+
const color = this.colorLists[listKey][closestColor.index];
|
|
82
100
|
|
|
83
101
|
return {
|
|
84
102
|
...color,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const seedrandom = require('seedrandom');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* getPaletteTitle
|
|
5
|
+
* @param {string[]} namesArr
|
|
6
|
+
* @param {int(0-1)} rnd1
|
|
7
|
+
* @param {int(0-1)} rnd2
|
|
8
|
+
* @param {int(0-1)} longPartFirst
|
|
9
|
+
* @param {RegExp} separatorRegex
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
module.exports = function getPaletteTitle(
|
|
14
|
+
namesArr, // array of names
|
|
15
|
+
separatorRegex = /(\s|-)+/g
|
|
16
|
+
) {
|
|
17
|
+
let localnames = [...namesArr];
|
|
18
|
+
|
|
19
|
+
const rng = seedrandom(namesArr.join('-'));
|
|
20
|
+
const rnd1 = rng();
|
|
21
|
+
const rnd2 = rng();
|
|
22
|
+
const longPartFirst = rng() < .5;
|
|
23
|
+
|
|
24
|
+
// select a random name from the list for the first word in the palette title
|
|
25
|
+
const indexFirst = Math.round(rnd1 * (localnames.length - 1));
|
|
26
|
+
|
|
27
|
+
// remove the selected name from the list
|
|
28
|
+
const firstName = localnames.splice(indexFirst, 1)[0];
|
|
29
|
+
|
|
30
|
+
// select a random name from the list as a last word in the palette title
|
|
31
|
+
const lastIndex = Math.round(rnd2 * (localnames.length - 1));
|
|
32
|
+
const lastName = localnames[lastIndex];
|
|
33
|
+
|
|
34
|
+
const partsFirst = firstName.split(separatorRegex);
|
|
35
|
+
const partsLast = lastName.split(separatorRegex);
|
|
36
|
+
|
|
37
|
+
if (longPartFirst) {
|
|
38
|
+
partsFirst.length > 1 ?
|
|
39
|
+
partsFirst.pop() :
|
|
40
|
+
partsFirst[0] = `${partsFirst[0]} `;
|
|
41
|
+
return partsFirst.join('') + partsLast.pop();
|
|
42
|
+
} else {
|
|
43
|
+
partsLast.length > 1 ?
|
|
44
|
+
partsLast.shift() :
|
|
45
|
+
partsLast[0] = ` ${partsLast[0]}`;
|
|
46
|
+
return partsFirst.shift() + partsLast.join('');
|
|
47
|
+
}
|
|
48
|
+
}
|
package/scripts/server.js
CHANGED
|
@@ -2,6 +2,7 @@ const http = require('http');
|
|
|
2
2
|
const url = require('url');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const zlib = require('zlib');
|
|
5
|
+
const colorNameLists = require('color-name-lists');
|
|
5
6
|
const colors = JSON.parse(
|
|
6
7
|
fs.readFileSync(__dirname + '/../dist/colornames.json', 'utf8')
|
|
7
8
|
);
|
|
@@ -9,6 +10,7 @@ const colorsBestOf = JSON.parse(
|
|
|
9
10
|
fs.readFileSync(__dirname + '/../dist/colornames.bestof.json', 'utf8')
|
|
10
11
|
);
|
|
11
12
|
const FindColors = require('./findColors.js');
|
|
13
|
+
const getPaletteTitle = require('./generatePaletteName.js');
|
|
12
14
|
const port = process.env.PORT || 8080;
|
|
13
15
|
const currentVersion = 'v1';
|
|
14
16
|
const urlNameSubpath = 'names';
|
|
@@ -26,7 +28,18 @@ const responseHeaderObj = {
|
|
|
26
28
|
'Content-Type': 'application/json; charset=utf-8',
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
// [{name: 'red', value: '#f00'}, ...]
|
|
32
|
+
const colorsLists = {
|
|
33
|
+
default: colors,
|
|
34
|
+
colors: colors,
|
|
35
|
+
bestOf: colorsBestOf,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Object.assign(colorsLists, colorNameLists);
|
|
39
|
+
|
|
40
|
+
const avalibleColorNameLists = Object.keys(colorsLists);
|
|
41
|
+
|
|
42
|
+
const findColors = new FindColors(colorsLists);
|
|
30
43
|
|
|
31
44
|
/**
|
|
32
45
|
* validates a hex color
|
|
@@ -53,7 +66,7 @@ const httpRespond = (response, responseObj = {}, statusCode = 200) => {
|
|
|
53
66
|
|
|
54
67
|
const respondNameSearch = (
|
|
55
68
|
searchParams = new URLSearchParams(''),
|
|
56
|
-
|
|
69
|
+
listKey = 'default',
|
|
57
70
|
requestUrl,
|
|
58
71
|
request,
|
|
59
72
|
response
|
|
@@ -77,13 +90,13 @@ const respondNameSearch = (
|
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
return httpRespond(response, {
|
|
80
|
-
colors: findColors.searchNames(searchString,
|
|
93
|
+
colors: findColors.searchNames(searchString, listKey),
|
|
81
94
|
}, 200);
|
|
82
95
|
};
|
|
83
96
|
|
|
84
97
|
const respondValueSearch = (
|
|
85
98
|
searchParams = new URLSearchParams(''),
|
|
86
|
-
|
|
99
|
+
listKey = 'default',
|
|
87
100
|
requestUrl,
|
|
88
101
|
request,
|
|
89
102
|
response
|
|
@@ -116,10 +129,32 @@ const respondValueSearch = (
|
|
|
116
129
|
}}, 404);
|
|
117
130
|
}
|
|
118
131
|
|
|
132
|
+
let paletteTitle;
|
|
133
|
+
let colorsResponse;
|
|
134
|
+
|
|
135
|
+
if (urlColorList[0]) {
|
|
136
|
+
colorsResponse = findColors.getNamesForValues(
|
|
137
|
+
urlColorList, uniqueMode, listKey
|
|
138
|
+
);
|
|
139
|
+
} else {
|
|
140
|
+
colorsResponse = colorsLists[listKey];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (urlColorList.length === 1) {
|
|
144
|
+
// if there is only one color, just return its name as palette title
|
|
145
|
+
paletteTitle = colorsResponse[0].name;
|
|
146
|
+
} else if (urlColorList.length > 1) {
|
|
147
|
+
// get a palette title for the returned colors
|
|
148
|
+
paletteTitle = getPaletteTitle(colorsResponse.map((color) => color.name));
|
|
149
|
+
} else {
|
|
150
|
+
// return all colors if no colors were given
|
|
151
|
+
paletteTitle = `All the ${listKey} names`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// actual http response
|
|
119
155
|
return httpRespond(response, {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
(goodNamesMode ? colorsBestOf : colors),
|
|
156
|
+
paletteTitle,
|
|
157
|
+
colors: colorsResponse,
|
|
123
158
|
}, 200);
|
|
124
159
|
};
|
|
125
160
|
|
|
@@ -159,10 +194,25 @@ const requestHandler = (request, response) => {
|
|
|
159
194
|
const goodNamesMode = searchParams.has('goodnamesonly')
|
|
160
195
|
&& searchParams.get('goodnamesonly') === 'true';
|
|
161
196
|
|
|
197
|
+
let listKey = searchParams.has('list')
|
|
198
|
+
&& searchParams.get('list');
|
|
199
|
+
|
|
200
|
+
listKey = goodNamesMode ? 'bestOf' : listKey;
|
|
201
|
+
listKey = listKey || 'default';
|
|
202
|
+
|
|
203
|
+
const isValidListKey = listKey && avalibleColorNameLists.includes(listKey);
|
|
204
|
+
|
|
205
|
+
if (!isValidListKey) {
|
|
206
|
+
return httpRespond(response, {error: {
|
|
207
|
+
status: 404,
|
|
208
|
+
message: `invalid list key: '${listKey}, available keys are: ${avalibleColorNameLists.join(', ')}`,
|
|
209
|
+
}}, 404);
|
|
210
|
+
}
|
|
211
|
+
|
|
162
212
|
if (!isNamesAPI) {
|
|
163
213
|
return respondValueSearch(
|
|
164
214
|
searchParams,
|
|
165
|
-
|
|
215
|
+
listKey,
|
|
166
216
|
requestUrl,
|
|
167
217
|
request,
|
|
168
218
|
response
|
|
@@ -170,7 +220,7 @@ const requestHandler = (request, response) => {
|
|
|
170
220
|
} else {
|
|
171
221
|
return respondNameSearch(
|
|
172
222
|
searchParams,
|
|
173
|
-
|
|
223
|
+
listKey,
|
|
174
224
|
requestUrl,
|
|
175
225
|
request,
|
|
176
226
|
response
|