vue3-draggable-resizable
Version:
[Vue3 Component] 拖拽缩放并具有自动吸附对齐、参考线等功能
511 lines (510 loc) • 20.9 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
exports.__esModule = true;
exports.watchProps = exports.initResizeHandle = exports.initDraggableContainer = exports.initLimitSizeAndMethods = exports.initParent = exports.initState = exports.useState = void 0;
var vue_1 = require("vue");
var utils_1 = require("./utils");
function useState(initialState) {
var state = vue_1.ref(initialState);
var setState = function (value) {
state.value = value;
return value;
};
return [state, setState];
}
exports.useState = useState;
function initState(props, emit) {
var _a = useState(props.initW), width = _a[0], setWidth = _a[1];
var _b = useState(props.initH), height = _b[0], setHeight = _b[1];
var _c = useState(props.x), left = _c[0], setLeft = _c[1];
var _d = useState(props.y), top = _d[0], setTop = _d[1];
var _e = useState(props.active), enable = _e[0], setEnable = _e[1];
var _f = useState(false), dragging = _f[0], setDragging = _f[1];
var _g = useState(false), resizing = _g[0], setResizing = _g[1];
var _h = useState(''), resizingHandle = _h[0], setResizingHandle = _h[1];
var _j = useState(Infinity), resizingMaxWidth = _j[0], setResizingMaxWidth = _j[1];
var _k = useState(Infinity), resizingMaxHeight = _k[0], setResizingMaxHeight = _k[1];
var _l = useState(props.minW), resizingMinWidth = _l[0], setResizingMinWidth = _l[1];
var _m = useState(props.minH), resizingMinHeight = _m[0], setResizingMinHeight = _m[1];
var aspectRatio = vue_1.computed(function () { return height.value / width.value; });
vue_1.watch(width, function (newVal) {
emit('update:w', newVal);
}, { immediate: true });
vue_1.watch(height, function (newVal) {
emit('update:h', newVal);
}, { immediate: true });
vue_1.watch(top, function (newVal) {
emit('update:y', newVal);
});
vue_1.watch(left, function (newVal) {
emit('update:x', newVal);
});
vue_1.watch(enable, function (newVal, oldVal) {
emit('update:active', newVal);
if (!oldVal && newVal) {
emit('activated');
}
else if (oldVal && !newVal) {
emit('deactivated');
}
});
vue_1.watch(function () { return props.active; }, function (newVal) {
setEnable(newVal);
});
return {
id: utils_1.getId(),
width: width,
height: height,
top: top,
left: left,
enable: enable,
dragging: dragging,
resizing: resizing,
resizingHandle: resizingHandle,
resizingMaxHeight: resizingMaxHeight,
resizingMaxWidth: resizingMaxWidth,
resizingMinWidth: resizingMinWidth,
resizingMinHeight: resizingMinHeight,
aspectRatio: aspectRatio,
setEnable: setEnable,
setDragging: setDragging,
setResizing: setResizing,
setResizingHandle: setResizingHandle,
setResizingMaxHeight: setResizingMaxHeight,
setResizingMaxWidth: setResizingMaxWidth,
setResizingMinWidth: setResizingMinWidth,
setResizingMinHeight: setResizingMinHeight,
setWidth: function (val) { return setWidth(Math.floor(val)); },
setHeight: function (val) { return setHeight(Math.floor(val)); },
setTop: function (val) { return setTop(Math.floor(val)); },
setLeft: function (val) { return setLeft(Math.floor(val)); }
};
}
exports.initState = initState;
function initParent(containerRef) {
var parentWidth = vue_1.ref(0);
var parentHeight = vue_1.ref(0);
vue_1.onMounted(function () {
if (containerRef.value && containerRef.value.parentElement) {
var _a = utils_1.getElSize(containerRef.value.parentElement), width = _a.width, height = _a.height;
parentWidth.value = width;
parentHeight.value = height;
}
});
return {
parentWidth: parentWidth,
parentHeight: parentHeight
};
}
exports.initParent = initParent;
function initLimitSizeAndMethods(props, parentSize, containerProps) {
var width = containerProps.width, height = containerProps.height, left = containerProps.left, top = containerProps.top, resizingMaxWidth = containerProps.resizingMaxWidth, resizingMaxHeight = containerProps.resizingMaxHeight, resizingMinWidth = containerProps.resizingMinWidth, resizingMinHeight = containerProps.resizingMinHeight;
var setWidth = containerProps.setWidth, setHeight = containerProps.setHeight, setTop = containerProps.setTop, setLeft = containerProps.setLeft;
var parentWidth = parentSize.parentWidth, parentHeight = parentSize.parentHeight;
var limitProps = {
minWidth: vue_1.computed(function () {
return resizingMinWidth.value;
}),
minHeight: vue_1.computed(function () {
return resizingMinHeight.value;
}),
maxWidth: vue_1.computed(function () {
var max = Infinity;
if (props.parent) {
max = Math.min(parentWidth.value, resizingMaxWidth.value);
}
return max;
}),
maxHeight: vue_1.computed(function () {
var max = Infinity;
if (props.parent) {
max = Math.min(parentHeight.value, resizingMaxHeight.value);
}
return max;
}),
minLeft: vue_1.computed(function () {
return props.parent ? 0 : -Infinity;
}),
minTop: vue_1.computed(function () {
return props.parent ? 0 : -Infinity;
}),
maxLeft: vue_1.computed(function () {
return props.parent ? parentWidth.value - width.value : Infinity;
}),
maxTop: vue_1.computed(function () {
return props.parent ? parentHeight.value - height.value : Infinity;
})
};
var limitMethods = {
setWidth: function (val) {
if (props.disabledW) {
return width.value;
}
return setWidth(Math.min(limitProps.maxWidth.value, Math.max(limitProps.minWidth.value, val)));
},
setHeight: function (val) {
if (props.disabledH) {
return height.value;
}
return setHeight(Math.min(limitProps.maxHeight.value, Math.max(limitProps.minHeight.value, val)));
},
setTop: function (val) {
if (props.disabledY) {
return top.value;
}
return setTop(Math.min(limitProps.maxTop.value, Math.max(limitProps.minTop.value, val)));
},
setLeft: function (val) {
if (props.disabledX) {
return left.value;
}
return setLeft(Math.min(limitProps.maxLeft.value, Math.max(limitProps.minLeft.value, val)));
}
};
return __assign(__assign({}, limitProps), limitMethods);
}
exports.initLimitSizeAndMethods = initLimitSizeAndMethods;
var DOWN_HANDLES = ['mousedown', 'touchstart'];
var UP_HANDLES = ['mouseup', 'touchend'];
var MOVE_HANDLES = ['mousemove', 'touchmove'];
function getPosition(e) {
if ('touches' in e) {
return [e.touches[0].pageX, e.touches[0].pageY];
}
else {
return [e.pageX, e.pageY];
}
}
function initDraggableContainer(containerRef, containerProps, limitProps, draggable, emit, containerProvider, parentSize) {
var x = containerProps.left, y = containerProps.top, w = containerProps.width, h = containerProps.height, dragging = containerProps.dragging, id = containerProps.id;
var setDragging = containerProps.setDragging, setEnable = containerProps.setEnable, setResizing = containerProps.setResizing, setResizingHandle = containerProps.setResizingHandle;
var setTop = limitProps.setTop, setLeft = limitProps.setLeft;
var lstX = 0;
var lstY = 0;
var lstPageX = 0;
var lstPageY = 0;
var referenceLineMap = null;
var documentElement = document.documentElement;
var _unselect = function (e) {
var _a;
var target = e.target;
if (!((_a = containerRef.value) === null || _a === void 0 ? void 0 : _a.contains(target))) {
setEnable(false);
setDragging(false);
setResizing(false);
setResizingHandle('');
}
};
var handleUp = function () {
setDragging(false);
// document.documentElement.removeEventListener('mouseup', handleUp)
// document.documentElement.removeEventListener('mousemove', handleDrag)
utils_1.removeEvent(documentElement, UP_HANDLES, handleUp);
utils_1.removeEvent(documentElement, MOVE_HANDLES, handleDrag);
referenceLineMap = null;
if (containerProvider) {
containerProvider.updatePosition(id, {
x: x.value,
y: y.value,
w: w.value,
h: h.value
});
containerProvider.setMatchedLine(null);
}
};
var handleDrag = function (e) {
e.preventDefault();
if (!(dragging.value && containerRef.value))
return;
var _a = getPosition(e), pageX = _a[0], pageY = _a[1];
var deltaX = pageX - lstPageX;
var deltaY = pageY - lstPageY;
var newLeft = lstX + deltaX;
var newTop = lstY + deltaY;
if (referenceLineMap !== null) {
var widgetSelfLine = {
col: [newLeft, newLeft + w.value / 2, newLeft + w.value],
row: [newTop, newTop + h.value / 2, newTop + h.value]
};
var matchedLine = {
row: widgetSelfLine.row
.map(function (i, index) {
var match = null;
Object.values(referenceLineMap.row).forEach(function (referItem) {
if (i >= referItem.min && i <= referItem.max) {
match = referItem.value;
}
});
if (match !== null) {
if (index === 0) {
newTop = match;
}
else if (index === 1) {
newTop = Math.floor(match - h.value / 2);
}
else if (index === 2) {
newTop = Math.floor(match - h.value);
}
}
return match;
})
.filter(function (i) { return i !== null; }),
col: widgetSelfLine.col
.map(function (i, index) {
var match = null;
Object.values(referenceLineMap.col).forEach(function (referItem) {
if (i >= referItem.min && i <= referItem.max) {
match = referItem.value;
}
});
if (match !== null) {
if (index === 0) {
newLeft = match;
}
else if (index === 1) {
newLeft = Math.floor(match - w.value / 2);
}
else if (index === 2) {
newLeft = Math.floor(match - w.value);
}
}
return match;
})
.filter(function (i) { return i !== null; })
};
containerProvider.setMatchedLine(matchedLine);
}
emit('dragging', { x: setLeft(newLeft), y: setTop(newTop) });
};
var handleDown = function (e) {
if (!draggable.value)
return;
setDragging(true);
lstX = x.value;
lstY = y.value;
lstPageX = getPosition(e)[0];
lstPageY = getPosition(e)[1];
// document.documentElement.addEventListener('mousemove', handleDrag)
// document.documentElement.addEventListener('mouseup', handleUp)
utils_1.addEvent(documentElement, MOVE_HANDLES, handleDrag);
utils_1.addEvent(documentElement, UP_HANDLES, handleUp);
if (containerProvider && !containerProvider.disabled.value) {
referenceLineMap = utils_1.getReferenceLineMap(containerProvider, parentSize, id);
}
};
vue_1.watch(dragging, function (cur, pre) {
if (!pre && cur) {
emit('drag-start', { x: x.value, y: y.value });
setEnable(true);
setDragging(true);
}
else {
emit('drag-end', { x: x.value, y: y.value });
setDragging(false);
}
});
vue_1.onMounted(function () {
var el = containerRef.value;
if (!el)
return;
el.style.left = x + 'px';
el.style.top = y + 'px';
// document.documentElement.addEventListener('mousedown', _unselect)
// el.addEventListener('mousedown', handleDown)
utils_1.addEvent(documentElement, DOWN_HANDLES, _unselect);
utils_1.addEvent(el, DOWN_HANDLES, handleDown);
});
vue_1.onUnmounted(function () {
if (!containerRef.value)
return;
// document.documentElement.removeEventListener('mousedown', _unselect)
// document.documentElement.removeEventListener('mouseup', handleUp)
// document.documentElement.removeEventListener('mousemove', handleDrag)
utils_1.removeEvent(documentElement, DOWN_HANDLES, _unselect);
utils_1.removeEvent(documentElement, UP_HANDLES, handleUp);
utils_1.removeEvent(documentElement, MOVE_HANDLES, handleDrag);
});
return { containerRef: containerRef };
}
exports.initDraggableContainer = initDraggableContainer;
function initResizeHandle(containerProps, limitProps, parentSize, props, emit) {
var setWidth = limitProps.setWidth, setHeight = limitProps.setHeight, setLeft = limitProps.setLeft, setTop = limitProps.setTop;
var width = containerProps.width, height = containerProps.height, left = containerProps.left, top = containerProps.top, aspectRatio = containerProps.aspectRatio;
var setResizing = containerProps.setResizing, setResizingHandle = containerProps.setResizingHandle, setResizingMaxWidth = containerProps.setResizingMaxWidth, setResizingMaxHeight = containerProps.setResizingMaxHeight, setResizingMinWidth = containerProps.setResizingMinWidth, setResizingMinHeight = containerProps.setResizingMinHeight;
var parentWidth = parentSize.parentWidth, parentHeight = parentSize.parentHeight;
var lstW = 0;
var lstH = 0;
var lstX = 0;
var lstY = 0;
var lstPageX = 0;
var lstPageY = 0;
var tmpAspectRatio = 1;
var idx0 = '';
var idx1 = '';
var documentElement = document.documentElement;
var resizeHandleDrag = function (e) {
e.preventDefault();
var _a = getPosition(e), _pageX = _a[0], _pageY = _a[1];
var deltaX = _pageX - lstPageX;
var deltaY = _pageY - lstPageY;
var _deltaX = deltaX;
var _deltaY = deltaY;
if (props.lockAspectRatio) {
deltaX = Math.abs(deltaX);
deltaY = deltaX * tmpAspectRatio;
if (idx0 === 't') {
if (_deltaX < 0 || (idx1 === 'm' && _deltaY < 0)) {
deltaX = -deltaX;
deltaY = -deltaY;
}
}
else {
if (_deltaX < 0 || (idx1 === 'm' && _deltaY < 0)) {
deltaX = -deltaX;
deltaY = -deltaY;
}
}
}
if (idx0 === 't') {
setHeight(lstH - deltaY);
setTop(lstY - (height.value - lstH));
}
else if (idx0 === 'b') {
setHeight(lstH + deltaY);
}
if (idx1 === 'l') {
setWidth(lstW - deltaX);
setLeft(lstX - (width.value - lstW));
}
else if (idx1 === 'r') {
setWidth(lstW + deltaX);
}
emit('resizing', {
x: left.value,
y: top.value,
w: width.value,
h: height.value
});
};
var resizeHandleUp = function () {
emit('resize-end', {
x: left.value,
y: top.value,
w: width.value,
h: height.value
});
setResizingHandle('');
setResizing(false);
setResizingMaxWidth(Infinity);
setResizingMaxHeight(Infinity);
setResizingMinWidth(props.minW);
setResizingMinHeight(props.minH);
// document.documentElement.removeEventListener('mousemove', resizeHandleDrag)
// document.documentElement.removeEventListener('mouseup', resizeHandleUp)
utils_1.removeEvent(documentElement, MOVE_HANDLES, resizeHandleDrag);
utils_1.removeEvent(documentElement, UP_HANDLES, resizeHandleUp);
};
var resizeHandleDown = function (e, handleType) {
if (!props.resizable)
return;
e.stopPropagation();
setResizingHandle(handleType);
setResizing(true);
idx0 = handleType[0];
idx1 = handleType[1];
if (props.lockAspectRatio) {
if (['tl', 'tm', 'ml', 'bl'].includes(handleType)) {
idx0 = 't';
idx1 = 'l';
}
else {
idx0 = 'b';
idx1 = 'r';
}
}
var minHeight = props.minH;
var minWidth = props.minW;
if (props.lockAspectRatio) {
if (minHeight / minWidth > aspectRatio.value) {
minWidth = minHeight / aspectRatio.value;
}
else {
minHeight = minWidth * aspectRatio.value;
}
}
setResizingMinWidth(minWidth);
setResizingMinHeight(minHeight);
if (props.parent) {
var maxHeight = idx0 === 't' ? top.value + height.value : parentHeight.value - top.value;
var maxWidth = idx1 === 'l' ? left.value + width.value : parentWidth.value - left.value;
if (props.lockAspectRatio) {
if (maxHeight / maxWidth < aspectRatio.value) {
maxWidth = maxHeight / aspectRatio.value;
}
else {
maxHeight = maxWidth * aspectRatio.value;
}
}
setResizingMaxHeight(maxHeight);
setResizingMaxWidth(maxWidth);
}
lstW = width.value;
lstH = height.value;
lstX = left.value;
lstY = top.value;
var lstPagePosition = getPosition(e);
lstPageX = lstPagePosition[0];
lstPageY = lstPagePosition[1];
tmpAspectRatio = aspectRatio.value;
emit('resize-start', {
x: left.value,
y: top.value,
w: width.value,
h: height.value
});
// document.documentElement.addEventListener('mousemove', resizeHandleDrag)
// document.documentElement.addEventListener('mouseup', resizeHandleUp)
utils_1.addEvent(documentElement, MOVE_HANDLES, resizeHandleDrag);
utils_1.addEvent(documentElement, UP_HANDLES, resizeHandleUp);
};
vue_1.onUnmounted(function () {
// document.documentElement.removeEventListener('mouseup', resizeHandleDrag)
// document.documentElement.removeEventListener('mousemove', resizeHandleUp)
utils_1.removeEvent(documentElement, UP_HANDLES, resizeHandleUp);
utils_1.removeEvent(documentElement, MOVE_HANDLES, resizeHandleDrag);
});
var handlesFiltered = vue_1.computed(function () {
return props.resizable ? utils_1.filterHandles(props.handles) : [];
});
return {
handlesFiltered: handlesFiltered,
resizeHandleDown: resizeHandleDown
};
}
exports.initResizeHandle = initResizeHandle;
function watchProps(props, limits) {
var setWidth = limits.setWidth, setHeight = limits.setHeight, setLeft = limits.setLeft, setTop = limits.setTop;
vue_1.watch(function () { return props.w; }, function (newVal) {
setWidth(newVal);
});
vue_1.watch(function () { return props.h; }, function (newVal) {
setHeight(newVal);
});
vue_1.watch(function () { return props.x; }, function (newVal) {
setLeft(newVal);
});
vue_1.watch(function () { return props.y; }, function (newVal) {
setTop(newVal);
});
}
exports.watchProps = watchProps;
;