index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = Object.setPrototypeOf ||
  3. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  4. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  5. return function (d, b) {
  6. extendStatics(d, b);
  7. function __() { this.constructor = d; }
  8. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  9. };
  10. })();
  11. var __assign = (this && this.__assign) || Object.assign || function(t) {
  12. for (var s, i = 1, n = arguments.length; i < n; i++) {
  13. s = arguments[i];
  14. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  15. t[p] = s[p];
  16. }
  17. return t;
  18. };
  19. import * as React from "react";
  20. import { int, innerHeight, innerWidth, outerHeight, outerWidth, parseBounds } from '../utils';
  21. var doc = document;
  22. var Dragger = /** @class */ (function (_super) {
  23. __extends(Dragger, _super);
  24. function Dragger(props) {
  25. var _this = _super.call(this, props) || this;
  26. _this.state = {
  27. /** x轴位移,单位是px */
  28. x: _this.props.x || 0,
  29. /** y轴位移,单位是px */
  30. y: _this.props.y || 0,
  31. /**鼠标点击元素的原始位置,单位是px */
  32. originX: 0,
  33. originY: 0,
  34. isUserMove: true,
  35. /**已经移动的位移,单位是px */
  36. lastX: 0,
  37. lastY: 0,
  38. /**堆叠的层级 */
  39. zIndex: 1,
  40. w: _this.props.w || 0,
  41. h: _this.props.h || 0,
  42. lastW: 0,
  43. lastH: 0
  44. };
  45. _this.move = function (event) {
  46. var _a = _this.state, lastX = _a.lastX, lastY = _a.lastY;
  47. /* event.client - this.state.origin 表示的是移动的距离,
  48. * elX表示的是原来已经有的位移
  49. */
  50. var deltaX, deltaY;
  51. if (event.type.indexOf('mouse') >= 0) {
  52. deltaX = event.clientX - _this.state.originX + lastX;
  53. deltaY = event.clientY - _this.state.originY + lastY;
  54. }
  55. else {
  56. deltaX = event.touches[0].clientX - _this.state.originX + lastX;
  57. deltaY = event.touches[0].clientY - _this.state.originY + lastY;
  58. }
  59. var bounds = _this.props.bounds;
  60. if (bounds) {
  61. /**
  62. * 如果用户指定一个边界,那么在这里处理
  63. */
  64. var NewBounds = typeof bounds !== 'string' ? parseBounds(bounds) : bounds;
  65. /**
  66. * 网格式移动范围设定,永远移动 n 的倍数
  67. * 注意:设定移动范围的时候,一定要在判断bounds之前,否则会造成bounds不对齐
  68. */
  69. var grid = _this.props.grid;
  70. if (Array.isArray(grid) && grid.length === 2) {
  71. deltaX = Math.round(deltaX / grid[0]) * grid[0];
  72. deltaY = Math.round(deltaY / grid[1]) * grid[1];
  73. }
  74. if (_this.props.bounds === 'parent') {
  75. NewBounds = {
  76. left: int(_this.parent.style.paddingLeft) + int(_this.self.style.marginLeft) - _this.self.offsetLeft,
  77. top: int(_this.parent.style.paddingTop) + int(_this.self.style.marginTop) - _this.self.offsetTop,
  78. right: innerWidth(_this.parent) - outerWidth(_this.self) - _this.self.offsetLeft +
  79. int(_this.parent.style.paddingRight) - int(_this.self.style.marginRight),
  80. bottom: innerHeight(_this.parent) - outerHeight(_this.self) - _this.self.offsetTop +
  81. int(_this.parent.style.paddingBottom) - int(_this.self.style.marginBottom)
  82. };
  83. }
  84. /**
  85. * 保证不超出右边界和底部
  86. * keep element right and bot can not cross the bounds
  87. */
  88. if (NewBounds !== 'parent')
  89. deltaX = Math.min(deltaX, NewBounds.right);
  90. if (NewBounds !== 'parent')
  91. deltaY = Math.min(deltaY, NewBounds.bottom);
  92. /**
  93. * 保证不超出左边和上边
  94. * keep element left and top can not cross the bounds
  95. */
  96. if (NewBounds !== 'parent')
  97. deltaX = Math.max(deltaX, NewBounds.left);
  98. if (NewBounds !== 'parent')
  99. deltaY = Math.max(deltaY, NewBounds.top);
  100. }
  101. /**如果设置了x,y限制 */
  102. deltaX = _this.props.allowX ? deltaX : 0;
  103. deltaY = _this.props.allowY ? deltaY : 0;
  104. /**
  105. * 调整手感
  106. * 无论是向上移动还是向下移动,全部都是根据重力中心
  107. * */
  108. var height = _this.Ref.getClientRects()[0].height;
  109. var upNdown = _this.state.y - deltaY;
  110. var fixY = deltaY + (upNdown >= 0 ? 0 : height / 2);
  111. /**移动时回调,用于外部控制 */
  112. if (_this.props.onMove)
  113. _this.props.onMove(event, deltaX, fixY);
  114. _this.setState({
  115. x: deltaX,
  116. y: deltaY
  117. });
  118. };
  119. _this.onDragStart = function (event) {
  120. /** 保证用户在移动元素的时候不会选择到元素内部的东西 */
  121. doc.body.style.userSelect = 'none';
  122. // if (event.target.id !== 'dragact-handle') return
  123. /**
  124. * 把监听事件的回掉函数,绑定在document上
  125. * 当设置边界的时候,用户鼠标会离开元素的范围
  126. * 绑定在document上可以使得其依旧能够监听
  127. * 如果绑定在元素上,则鼠标离开元素,就不会再被监听了
  128. */
  129. if (event.type.indexOf('mouse') >= 0) {
  130. doc.addEventListener('mousemove', _this.move);
  131. doc.addEventListener('mouseup', _this.onDragEnd);
  132. }
  133. else {
  134. doc.addEventListener('touchmove', _this.move);
  135. doc.addEventListener('touchend', _this.onDragEnd);
  136. }
  137. if (_this.props.bounds === 'parent' &&
  138. /**为了让 这段代码不会重复执行 */
  139. (typeof _this.parent === 'undefined' || _this.parent === null)) {
  140. /**
  141. * 在这里我们将父节点缓存下来,保证当用户鼠标离开拖拽区域时,我们仍然能获取到父节点
  142. * what we do here is
  143. * making sure that we still can retrieve our parent when user's mouse left this node.
  144. */
  145. _this.parent = event.currentTarget.offsetParent; //todo
  146. /**
  147. * 我们自己
  148. * ourself
  149. */
  150. _this.self = event.currentTarget;
  151. }
  152. _this.props.onDragStart && _this.props.onDragStart(_this.state.x, _this.state.y);
  153. var originX, originY;
  154. if (event.type.indexOf('mouse') >= 0) {
  155. originX = event.clientX;
  156. originY = event.clientY;
  157. }
  158. else {
  159. originX = event.touches[0].clientX;
  160. originY = event.touches[0].clientY;
  161. }
  162. _this.setState({
  163. originX: originX,
  164. originY: originY,
  165. lastX: _this.state.x,
  166. lastY: _this.state.y,
  167. zIndex: 10
  168. });
  169. };
  170. _this.onDragEnd = function (event) {
  171. /** 取消用户选择限制,用户可以重新选择 */
  172. doc.body.style.userSelect = '';
  173. _this.parent = null;
  174. _this.self = null;
  175. if (event.type.indexOf('mouse') >= 0) {
  176. doc.removeEventListener('mousemove', _this.move);
  177. doc.removeEventListener('mouseup', _this.onDragEnd);
  178. }
  179. else {
  180. doc.removeEventListener('touchmove', _this.move);
  181. doc.removeEventListener('touchend', _this.onDragEnd);
  182. }
  183. _this.setState({
  184. zIndex: 1
  185. });
  186. _this.props.onDragEnd && _this.props.onDragEnd(event, _this.state.x, _this.state.y);
  187. };
  188. _this.onResizeStart = function (event) {
  189. /** 保证用户在移动元素的时候不会选择到元素内部的东西 */
  190. doc.body.style.userSelect = 'none';
  191. doc.addEventListener('mouseup', _this.onResizeEnd);
  192. doc.addEventListener('mousemove', _this.onResizing);
  193. var originX, originY;
  194. originX = event.clientX;
  195. originY = event.clientY;
  196. _this.props.onResizeStart && _this.props.onResizeStart(event, _this.state.w, _this.state.h);
  197. _this.setState({
  198. originX: originX,
  199. originY: originY,
  200. zIndex: 2,
  201. lastW: _this.state.w,
  202. lastH: _this.state.h
  203. });
  204. event.stopPropagation();
  205. };
  206. _this.onResizing = function (event) {
  207. /* event.client - this.state.origin 表示的是移动的距离,
  208. * elX表示的是原来已经有的位移
  209. */
  210. var deltaX, deltaY;
  211. if (event.type.indexOf('mouse') >= 0) {
  212. deltaX = event.clientX - _this.state.originX;
  213. deltaY = event.clientY - _this.state.originY;
  214. }
  215. else {
  216. deltaX = event.touches[0].clientX - _this.state.originX;
  217. deltaY = event.touches[0].clientY - _this.state.originY;
  218. }
  219. /**移动时回调,用于外部控制 */
  220. _this.props.onResizing && _this.props.onResizing(event, _this.state.w, _this.state.h);
  221. _this.setState({
  222. w: deltaX + _this.state.lastW,
  223. h: deltaY + _this.state.lastH
  224. });
  225. };
  226. _this.onResizeEnd = function (event) {
  227. doc.body.style.userSelect = '';
  228. doc.removeEventListener('mousemove', _this.onResizing);
  229. doc.removeEventListener('mouseup', _this.onResizeEnd);
  230. _this.props.onResizeEnd && _this.props.onResizeEnd(event, _this.state.w, _this.state.h);
  231. };
  232. _this.mixin = function () {
  233. var dragMix = {
  234. onMouseDown: _this.onDragStart,
  235. onTouchStart: _this.onDragStart,
  236. onTouchEnd: _this.onDragEnd,
  237. onMouseUp: _this.onDragEnd
  238. };
  239. var resizeMix = {
  240. onMouseDown: _this.onResizeStart,
  241. onMouseUp: _this.onResizeEnd
  242. };
  243. return {
  244. dragMix: dragMix, resizeMix: resizeMix
  245. };
  246. };
  247. // this.move = this.move.bind(this)
  248. // this.onDragEnd = this.onDragEnd.bind(this)
  249. _this.parent = null;
  250. _this.self = null;
  251. return _this;
  252. }
  253. Dragger.prototype.componentDidMount = function () {
  254. /**
  255. * 这个函数只会调用一次
  256. * 这个只是一个临时的解决方案,因为这样会使得元素进行两次刷新
  257. */
  258. // if (typeof this.props.x === 'number' &&
  259. // typeof this.props.y === 'number') {
  260. // this.setState({
  261. // x: this.props.x,
  262. // y: this.props.y
  263. // })
  264. // }
  265. };
  266. Dragger.prototype.componentWillReceiveProps = function (nextProps) {
  267. /**
  268. * 外部props 改变的时候更新元素的内部位置
  269. * 这个api设计其实很不好
  270. * 以后可能会修改掉
  271. */
  272. var isUserMove = nextProps.isUserMove;
  273. if (!isUserMove) {
  274. if (typeof nextProps.x === 'number' &&
  275. typeof nextProps.y === 'number') {
  276. this.setState({
  277. x: nextProps.x,
  278. y: nextProps.y,
  279. lastX: nextProps.x,
  280. lastY: nextProps.y,
  281. w: nextProps.w,
  282. h: nextProps.h
  283. });
  284. }
  285. }
  286. };
  287. Dragger.prototype.render = function () {
  288. var _this = this;
  289. var _a = this.state, x = _a.x, y = _a.y, w = _a.w, h = _a.h;
  290. var _b = this.props, style = _b.style, className = _b.className, canResize = _b.canResize;
  291. if (!this.props.isUserMove) {
  292. /**当外部设置其props的x,y初始属性的时候,我们在这里设置元素的初始位移 */
  293. x = this.props.x ? this.props.x : 0;
  294. y = this.props.y ? this.props.y : 0;
  295. if (style) {
  296. w = style.width ? style.width : w;
  297. h = style.height ? style.height : h;
  298. }
  299. }
  300. if (style) {
  301. //使得初始化的时候,不会有从0-1缩放动画
  302. w = w === 0 ? style.width : w;
  303. h = h === 0 ? style.height : h;
  304. }
  305. var _c = this.mixin(), dragMix = _c.dragMix, resizeMix = _c.resizeMix;
  306. /**主要是为了让用户定义自己的className去修改css */
  307. // const fixedClassName = typeof className === 'undefined' ? '' : className + ' '
  308. resizeMix;
  309. canResize;
  310. className;
  311. var provided = {
  312. style: __assign({}, style, { touchAction: 'none!important', transform: "translate(" + x + "px," + y + "px)", width: w, height: h }),
  313. ref: function (node) { return _this.Ref = node; }
  314. };
  315. return this.props.children(provided, dragMix, resizeMix);
  316. };
  317. /**
  318. * 初始变量设置
  319. */
  320. Dragger.defaultProps = {
  321. allowX: true,
  322. allowY: true,
  323. isUserMove: true
  324. };
  325. return Dragger;
  326. }(React.Component));
  327. export { Dragger };
  328. // return (
  329. // <div className={`${fixedClassName}WrapDragger`}
  330. // ref={'dragger'}
  331. // >
  332. // {this.props.children(provided)}
  333. // {canResize !== false ?
  334. // <span
  335. // {...resizeMix}
  336. // style={{
  337. // position: 'absolute',
  338. // width: 10, height: 10, right: 2, bottom: 2, cursor: 'se-resize',
  339. // borderRight: '2px solid rgba(15,15,15,0.2)',
  340. // borderBottom: '2px solid rgba(15,15,15,0.2)'
  341. // }}
  342. // /> : null}
  343. // </div>
  344. // )