SnapContext.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import {
  2. forEach
  3. } from 'min-dash';
  4. import {
  5. snapTo
  6. } from './SnapUtil';
  7. /**
  8. * A snap context, containing the (possibly incomplete)
  9. * mappings of drop targets (to identify the snapping)
  10. * to computed snap points.
  11. */
  12. export default function SnapContext() {
  13. /**
  14. * Map<String, SnapPoints> mapping drop targets to
  15. * a list of possible snappings.
  16. *
  17. * @type {Object}
  18. */
  19. this._targets = {};
  20. /**
  21. * Map<String, Point> initial positioning of element
  22. * regarding various snap directions.
  23. *
  24. * @type {Object}
  25. */
  26. this._snapOrigins = {};
  27. /**
  28. * List of snap locations
  29. *
  30. * @type {Array<String>}
  31. */
  32. this._snapLocations = [];
  33. /**
  34. * Map<String, Array<Point>> of default snapping locations
  35. *
  36. * @type {Object}
  37. */
  38. this._defaultSnaps = {};
  39. }
  40. SnapContext.prototype.getSnapOrigin = function(snapLocation) {
  41. return this._snapOrigins[snapLocation];
  42. };
  43. SnapContext.prototype.setSnapOrigin = function(snapLocation, initialValue) {
  44. this._snapOrigins[snapLocation] = initialValue;
  45. if (this._snapLocations.indexOf(snapLocation) === -1) {
  46. this._snapLocations.push(snapLocation);
  47. }
  48. };
  49. SnapContext.prototype.addDefaultSnap = function(type, point) {
  50. var snapValues = this._defaultSnaps[type];
  51. if (!snapValues) {
  52. snapValues = this._defaultSnaps[type] = [];
  53. }
  54. snapValues.push(point);
  55. };
  56. /**
  57. * Return a number of initialized snaps, i.e. snap locations such as
  58. * top-left, mid, bottom-right and so forth.
  59. *
  60. * @return {Array<String>} snapLocations
  61. */
  62. SnapContext.prototype.getSnapLocations = function() {
  63. return this._snapLocations;
  64. };
  65. /**
  66. * Set the snap locations for this context.
  67. *
  68. * The order of locations determines precedence.
  69. *
  70. * @param {Array<String>} snapLocations
  71. */
  72. SnapContext.prototype.setSnapLocations = function(snapLocations) {
  73. this._snapLocations = snapLocations;
  74. };
  75. /**
  76. * Get snap points for a given target
  77. *
  78. * @param {Element|String} target
  79. */
  80. SnapContext.prototype.pointsForTarget = function(target) {
  81. var targetId = target.id || target;
  82. var snapPoints = this._targets[targetId];
  83. if (!snapPoints) {
  84. snapPoints = this._targets[targetId] = new SnapPoints();
  85. snapPoints.initDefaults(this._defaultSnaps);
  86. }
  87. return snapPoints;
  88. };
  89. /**
  90. * Creates the snap points and initializes them with the
  91. * given default values.
  92. *
  93. * @param {Object<String, Array<Point>>} [defaultPoints]
  94. */
  95. function SnapPoints(defaultSnaps) {
  96. /**
  97. * Map<String, Map<(x|y), Array<Number>>> mapping snap locations,
  98. * i.e. top-left, bottom-right, center to actual snap values.
  99. *
  100. * @type {Object}
  101. */
  102. this._snapValues = {};
  103. }
  104. SnapPoints.prototype.add = function(snapLocation, point) {
  105. var snapValues = this._snapValues[snapLocation];
  106. if (!snapValues) {
  107. snapValues = this._snapValues[snapLocation] = { x: [], y: [] };
  108. }
  109. if (snapValues.x.indexOf(point.x) === -1) {
  110. snapValues.x.push(point.x);
  111. }
  112. if (snapValues.y.indexOf(point.y) === -1) {
  113. snapValues.y.push(point.y);
  114. }
  115. };
  116. SnapPoints.prototype.snap = function(point, snapLocation, axis, tolerance) {
  117. var snappingValues = this._snapValues[snapLocation];
  118. return snappingValues && snapTo(point[axis], snappingValues[axis], tolerance);
  119. };
  120. /**
  121. * Initialize a number of default snapping points.
  122. *
  123. * @param {Object} defaultSnaps
  124. */
  125. SnapPoints.prototype.initDefaults = function(defaultSnaps) {
  126. var self = this;
  127. forEach(defaultSnaps || {}, function(snapPoints, snapLocation) {
  128. forEach(snapPoints, function(point) {
  129. self.add(snapLocation, point);
  130. });
  131. });
  132. };