react-moveable
Version:
A React Component that create Moveable, Draggable, Resizable, Scalable, Rotatable, Warpable, Pinchable, Groupable.
201 lines (177 loc) • 6.34 kB
text/typescript
import { getDragDist, setDragStart } from "../DraggerUtils";
import { throttleArray, triggerEvent, prefix } from "../utils";
import { minus, plus } from "@moveable/matrix";
import MoveableManager from "../MoveableManager";
import { DraggableProps, OnDrag, OnDragGroup, OnDragGroupStart, OnDragStart } from "../types";
import MoveableGroup from "../MoveableGroup";
import { triggerChildAble } from "../groupUtils";
import { hasClass } from "@daybrush/utils";
export default {
name: "draggable",
dragStart(
moveable: MoveableManager<DraggableProps>,
{ datas, clientX, clientY, parentEvent, parentDragger }: any,
) {
const state = moveable.state;
const {
targetTransform,
target,
dragger,
} = state;
if (dragger) {
return false;
}
state.dragger = parentDragger || moveable.targetDragger;
const style = window.getComputedStyle(target!);
datas.datas = {};
datas.left = parseFloat(style.left || "") || 0;
datas.top = parseFloat(style.top || "") || 0;
datas.bottom = parseFloat(style.bottom || "") || 0;
datas.right = parseFloat(style.right || "") || 0;
datas.transform = targetTransform;
datas.startTranslate = [0, 0];
setDragStart(moveable, { datas });
datas.prevDist = [0, 0];
datas.prevBeforeDist = [0, 0];
datas.isDrag = false;
const params: OnDragStart = {
datas: datas.datas,
target: target!,
clientX,
clientY,
set: (translate: number[]) => {
datas.startTranslate = translate;
},
};
const result = parentEvent || triggerEvent(moveable, "onDragStart", params);
if (result !== false) {
datas.isDrag = true;
} else {
state.dragger = null;
datas.isPinch = false;
}
return datas.isDrag ? params : false;
},
drag(
moveable: MoveableManager<DraggableProps>,
{ datas, distX, distY, clientX, clientY, parentEvent }: any,
): OnDrag | undefined {
const { isPinch, isDrag, prevDist, prevBeforeDist, transform, startTranslate } = datas;
if (!isDrag) {
return;
}
const props = moveable.props;
const parentMoveable = props.parentMoveable;
const throttleDrag = parentEvent ? 0 : (props.throttleDrag || 0);
const target = moveable.state.target;
const beforeTranslate = plus(getDragDist({ datas, distX, distY }, true), startTranslate);
const translate = plus(getDragDist({ datas, distX, distY }, false), startTranslate);
throttleArray(translate, throttleDrag);
throttleArray(beforeTranslate, throttleDrag);
const beforeDist = minus(beforeTranslate, startTranslate);
const dist = minus(translate, startTranslate);
const delta = minus(dist, prevDist);
const beforeDelta = minus(beforeDist, prevBeforeDist);
datas.prevDist = dist;
datas.prevBeforeDist = beforeDist;
const left = datas.left + beforeDist[0];
const top = datas.top + beforeDist[1];
const right = datas.right - beforeDist[0];
const bottom = datas.bottom - beforeDist[1];
const nextTransform = `${transform} translate(${dist[0]}px, ${dist[1]}px)`;
if (!parentEvent && !parentMoveable && delta.every(num => !num) && beforeDelta.some(num => !num)) {
return;
}
const params = {
datas: datas.datas,
target: target!,
transform: nextTransform,
dist,
delta,
translate,
beforeDist,
beforeDelta,
beforeTranslate,
left,
top,
right,
bottom,
clientX,
clientY,
isPinch,
};
!parentEvent && triggerEvent(moveable, "onDrag", params);
return params;
},
dragEnd(
moveable: MoveableManager<DraggableProps>,
{ parentEvent, datas, isDrag, clientX, clientY }: any,
) {
if (!datas.isDrag) {
return;
}
moveable.state.dragger = null;
datas.isDrag = false;
!parentEvent && triggerEvent(moveable, "onDragEnd", {
target: moveable.state.target!,
isDrag,
clientX,
clientY,
datas: datas.datas,
});
return isDrag;
},
dragGroupCondition(target: HTMLElement | SVGElement) {
return hasClass(target, prefix("area"));
},
dragGroupStart(moveable: MoveableGroup, e: any) {
const datas = e.datas;
const params = this.dragStart(moveable, e);
if (!params) {
return false;
}
const events = triggerChildAble(moveable, this, "dragStart", datas, e);
const nextParams: OnDragGroupStart = {
...params,
targets: moveable.props.targets!,
events,
};
const result = triggerEvent(moveable, "onDragGroupStart", nextParams);
datas.isDrag = result !== false;
return datas.isDrag ? params : false;
},
dragGroup(moveable: MoveableGroup, e: any) {
const datas = e.datas;
if (!datas.isDrag) {
return;
}
const events = triggerChildAble(moveable, this, "drag", datas, e);
const params = this.drag(moveable, e);
if (!params) {
return;
}
const nextParams: OnDragGroup = {
targets: moveable.props.targets!,
events,
...params,
};
triggerEvent(moveable, "onDragGroup", nextParams);
return nextParams;
},
dragGroupEnd(moveable: MoveableGroup, e: any) {
const { clientX, clientY, isDrag, datas } = e;
if (!datas.isDrag) {
return;
}
this.dragEnd(moveable, e);
triggerChildAble(moveable, this, "dragEnd", datas, e);
triggerEvent(moveable, "onDragGroupEnd", {
targets: moveable.props.targets!,
isDrag,
clientX,
clientY,
datas: datas.datas,
});
return isDrag;
},
};