615d7c7c682a970667e9c32c410d05968df770e00fde416bd100488f0d1d73c70b773904c8843efd53aa8ec83ed3770843a7d7903f3e71008001a26bb69a04 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
  2. // randomColor by David Merfield under the CC0 license
  3. // https://github.com/davidmerfield/randomColor/
  4. import { TinyColor } from './index.js';
  5. export function random(options) {
  6. if (options === void 0) { options = {}; }
  7. // Check if we need to generate multiple colors
  8. if (options.count !== undefined &&
  9. options.count !== null) {
  10. var totalColors = options.count;
  11. var colors = [];
  12. options.count = undefined;
  13. while (totalColors > colors.length) {
  14. // Since we're generating multiple colors,
  15. // incremement the seed. Otherwise we'd just
  16. // generate the same color each time...
  17. options.count = null;
  18. if (options.seed) {
  19. options.seed += 1;
  20. }
  21. colors.push(random(options));
  22. }
  23. options.count = totalColors;
  24. return colors;
  25. }
  26. // First we pick a hue (H)
  27. var h = pickHue(options.hue, options.seed);
  28. // Then use H to determine saturation (S)
  29. var s = pickSaturation(h, options);
  30. // Then use S and H to determine brightness (B).
  31. var v = pickBrightness(h, s, options);
  32. var res = { h: h, s: s, v: v };
  33. if (options.alpha !== undefined) {
  34. res.a = options.alpha;
  35. }
  36. // Then we return the HSB color in the desired format
  37. return new TinyColor(res);
  38. }
  39. function pickHue(hue, seed) {
  40. var hueRange = getHueRange(hue);
  41. var res = randomWithin(hueRange, seed);
  42. // Instead of storing red as two seperate ranges,
  43. // we group them, using negative numbers
  44. if (res < 0) {
  45. res = 360 + res;
  46. }
  47. return res;
  48. }
  49. function pickSaturation(hue, options) {
  50. if (options.hue === 'monochrome') {
  51. return 0;
  52. }
  53. if (options.luminosity === 'random') {
  54. return randomWithin([0, 100], options.seed);
  55. }
  56. var saturationRange = getColorInfo(hue).saturationRange;
  57. var sMin = saturationRange[0];
  58. var sMax = saturationRange[1];
  59. switch (options.luminosity) {
  60. case 'bright':
  61. sMin = 55;
  62. break;
  63. case 'dark':
  64. sMin = sMax - 10;
  65. break;
  66. case 'light':
  67. sMax = 55;
  68. break;
  69. default:
  70. break;
  71. }
  72. return randomWithin([sMin, sMax], options.seed);
  73. }
  74. function pickBrightness(H, S, options) {
  75. var bMin = getMinimumBrightness(H, S);
  76. var bMax = 100;
  77. switch (options.luminosity) {
  78. case 'dark':
  79. bMax = bMin + 20;
  80. break;
  81. case 'light':
  82. bMin = (bMax + bMin) / 2;
  83. break;
  84. case 'random':
  85. bMin = 0;
  86. bMax = 100;
  87. break;
  88. default:
  89. break;
  90. }
  91. return randomWithin([bMin, bMax], options.seed);
  92. }
  93. function getMinimumBrightness(H, S) {
  94. var lowerBounds = getColorInfo(H).lowerBounds;
  95. for (var i = 0; i < lowerBounds.length - 1; i++) {
  96. var s1 = lowerBounds[i][0];
  97. var v1 = lowerBounds[i][1];
  98. var s2 = lowerBounds[i + 1][0];
  99. var v2 = lowerBounds[i + 1][1];
  100. if (S >= s1 && S <= s2) {
  101. var m = (v2 - v1) / (s2 - s1);
  102. var b = v1 - m * s1;
  103. return m * S + b;
  104. }
  105. }
  106. return 0;
  107. }
  108. function getHueRange(colorInput) {
  109. var num = parseInt(colorInput, 10);
  110. if (!Number.isNaN(num) && num < 360 && num > 0) {
  111. return [num, num];
  112. }
  113. if (typeof colorInput === 'string') {
  114. var namedColor = bounds.find(function (n) { return n.name === colorInput; });
  115. if (namedColor) {
  116. var color = defineColor(namedColor);
  117. if (color.hueRange) {
  118. return color.hueRange;
  119. }
  120. }
  121. var parsed = new TinyColor(colorInput);
  122. if (parsed.isValid) {
  123. var hue = parsed.toHsv().h;
  124. return [hue, hue];
  125. }
  126. }
  127. return [0, 360];
  128. }
  129. function getColorInfo(hue) {
  130. // Maps red colors to make picking hue easier
  131. if (hue >= 334 && hue <= 360) {
  132. hue -= 360;
  133. }
  134. for (var _i = 0, bounds_1 = bounds; _i < bounds_1.length; _i++) {
  135. var bound = bounds_1[_i];
  136. var color = defineColor(bound);
  137. if (color.hueRange && hue >= color.hueRange[0] && hue <= color.hueRange[1]) {
  138. return color;
  139. }
  140. }
  141. throw Error('Color not found');
  142. }
  143. function randomWithin(range, seed) {
  144. if (seed === undefined) {
  145. return Math.floor(range[0] + Math.random() * (range[1] + 1 - range[0]));
  146. }
  147. // Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
  148. var max = range[1] || 1;
  149. var min = range[0] || 0;
  150. seed = (seed * 9301 + 49297) % 233280;
  151. var rnd = seed / 233280.0;
  152. return Math.floor(min + rnd * (max - min));
  153. }
  154. function defineColor(bound) {
  155. var sMin = bound.lowerBounds[0][0];
  156. var sMax = bound.lowerBounds[bound.lowerBounds.length - 1][0];
  157. var bMin = bound.lowerBounds[bound.lowerBounds.length - 1][1];
  158. var bMax = bound.lowerBounds[0][1];
  159. return {
  160. name: bound.name,
  161. hueRange: bound.hueRange,
  162. lowerBounds: bound.lowerBounds,
  163. saturationRange: [sMin, sMax],
  164. brightnessRange: [bMin, bMax],
  165. };
  166. }
  167. /**
  168. * @hidden
  169. */
  170. export var bounds = [
  171. {
  172. name: 'monochrome',
  173. hueRange: null,
  174. lowerBounds: [
  175. [0, 0],
  176. [100, 0],
  177. ],
  178. },
  179. {
  180. name: 'red',
  181. hueRange: [-26, 18],
  182. lowerBounds: [
  183. [20, 100],
  184. [30, 92],
  185. [40, 89],
  186. [50, 85],
  187. [60, 78],
  188. [70, 70],
  189. [80, 60],
  190. [90, 55],
  191. [100, 50],
  192. ],
  193. },
  194. {
  195. name: 'orange',
  196. hueRange: [19, 46],
  197. lowerBounds: [
  198. [20, 100],
  199. [30, 93],
  200. [40, 88],
  201. [50, 86],
  202. [60, 85],
  203. [70, 70],
  204. [100, 70],
  205. ],
  206. },
  207. {
  208. name: 'yellow',
  209. hueRange: [47, 62],
  210. lowerBounds: [
  211. [25, 100],
  212. [40, 94],
  213. [50, 89],
  214. [60, 86],
  215. [70, 84],
  216. [80, 82],
  217. [90, 80],
  218. [100, 75],
  219. ],
  220. },
  221. {
  222. name: 'green',
  223. hueRange: [63, 178],
  224. lowerBounds: [
  225. [30, 100],
  226. [40, 90],
  227. [50, 85],
  228. [60, 81],
  229. [70, 74],
  230. [80, 64],
  231. [90, 50],
  232. [100, 40],
  233. ],
  234. },
  235. {
  236. name: 'blue',
  237. hueRange: [179, 257],
  238. lowerBounds: [
  239. [20, 100],
  240. [30, 86],
  241. [40, 80],
  242. [50, 74],
  243. [60, 60],
  244. [70, 52],
  245. [80, 44],
  246. [90, 39],
  247. [100, 35],
  248. ],
  249. },
  250. {
  251. name: 'purple',
  252. hueRange: [258, 282],
  253. lowerBounds: [
  254. [20, 100],
  255. [30, 87],
  256. [40, 79],
  257. [50, 70],
  258. [60, 65],
  259. [70, 59],
  260. [80, 52],
  261. [90, 45],
  262. [100, 42],
  263. ],
  264. },
  265. {
  266. name: 'pink',
  267. hueRange: [283, 334],
  268. lowerBounds: [
  269. [20, 100],
  270. [30, 90],
  271. [40, 86],
  272. [60, 84],
  273. [80, 80],
  274. [90, 75],
  275. [100, 73],
  276. ],
  277. },
  278. ];