contrastReverse.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { maxIndex } from 'd3-array';
  2. import { parseToRGB } from '../utils/color';
  3. function getsRGB(s) {
  4. let c = s / 255;
  5. c = c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
  6. return c;
  7. }
  8. function getL(r, g, b) {
  9. return 0.2126 * getsRGB(r) + 0.7152 * getsRGB(g) + 0.0722 * getsRGB(b);
  10. }
  11. /**
  12. * Calculate the contrast. see https://webaim.org/resources/contrastchecker/
  13. * @param foreground
  14. * @param background
  15. */
  16. function contrast(foreground, background) {
  17. const { r, g, b } = foreground;
  18. const { r: rb, g: gb, b: bb } = background;
  19. const L1 = getL(r, g, b);
  20. const L2 = getL(rb, gb, bb);
  21. return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
  22. }
  23. /**
  24. * Reverse color for max contrast.
  25. */
  26. function mostContrast(color, palette) {
  27. const i = maxIndex(palette, (c) => contrast(color, parseToRGB(c)));
  28. return palette[i];
  29. }
  30. /**
  31. * Reverse the label color when the contrast is lower then `threshold`.
  32. * The default value of `threshold` is 4.5.
  33. * More about contract, see https://webaim.org/resources/contrastchecker/
  34. */
  35. export const ContrastReverse = (options) => {
  36. const { threshold = 4.5, palette = ['#000', '#fff'] } = options;
  37. return (labels, coordinate) => {
  38. labels.forEach((l) => {
  39. const background = l.attr('dependentElement').parsedStyle.fill;
  40. const foreground = l.parsedStyle.fill;
  41. const c = contrast(foreground, background);
  42. if (c < threshold)
  43. l.attr('fill', mostContrast(background, palette));
  44. });
  45. return labels;
  46. };
  47. };
  48. //# sourceMappingURL=contrastReverse.js.map