getRoundedOffsets.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. /**
  2. * @function
  3. * @memberof Popper.Utils
  4. * @argument {Object} data - The data object generated by `update` method
  5. * @argument {Boolean} shouldRound - If the offsets should be rounded at all
  6. * @returns {Object} The popper's position offsets rounded
  7. *
  8. * The tale of pixel-perfect positioning. It's still not 100% perfect, but as
  9. * good as it can be within reason.
  10. * Discussion here: https://github.com/FezVrasta/popper.js/pull/715
  11. *
  12. * Low DPI screens cause a popper to be blurry if not using full pixels (Safari
  13. * as well on High DPI screens).
  14. *
  15. * Firefox prefers no rounding for positioning and does not have blurriness on
  16. * high DPI screens.
  17. *
  18. * Only horizontal placement and left/right values need to be considered.
  19. */
  20. export default function getRoundedOffsets(data, shouldRound) {
  21. const { popper, reference } = data.offsets;
  22. const { round, floor } = Math;
  23. const noRound = v => v;
  24. const referenceWidth = round(reference.width);
  25. const popperWidth = round(popper.width);
  26. const isVertical = ['left', 'right'].indexOf(data.placement) !== -1;
  27. const isVariation = data.placement.indexOf('-') !== -1;
  28. const sameWidthParity = referenceWidth % 2 === popperWidth % 2;
  29. const bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;
  30. const horizontalToInteger = !shouldRound
  31. ? noRound
  32. : isVertical || isVariation || sameWidthParity
  33. ? round
  34. : floor;
  35. const verticalToInteger = !shouldRound ? noRound : round;
  36. return {
  37. left: horizontalToInteger(
  38. bothOddWidth && !isVariation && shouldRound
  39. ? popper.left - 1
  40. : popper.left
  41. ),
  42. top: verticalToInteger(popper.top),
  43. bottom: verticalToInteger(popper.bottom),
  44. right: horizontalToInteger(popper.right),
  45. };
  46. }