123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122 |
- <script lang="ts" setup>
- /**
- * This components is refactored from vue-drag-resize: https://github.com/kirillmurashov/vue-drag-resize
- */
- import {
- computed,
- getCurrentInstance,
- nextTick,
- onBeforeUnmount,
- onMounted,
- ref,
- toRefs,
- watch,
- } from 'vue';
- const props = defineProps({
- stickSize: {
- type: Number,
- default: 8,
- },
- parentScaleX: {
- type: Number,
- default: 1,
- },
- parentScaleY: {
- type: Number,
- default: 1,
- },
- isActive: {
- type: Boolean,
- default: false,
- },
- preventActiveBehavior: {
- type: Boolean,
- default: false,
- },
- isDraggable: {
- type: Boolean,
- default: true,
- },
- isResizable: {
- type: Boolean,
- default: true,
- },
- aspectRatio: {
- type: Boolean,
- default: false,
- },
- parentLimitation: {
- type: Boolean,
- default: false,
- },
- snapToGrid: {
- type: Boolean,
- default: false,
- },
- gridX: {
- type: Number,
- default: 50,
- validator(val: number) {
- return val >= 0;
- },
- },
- gridY: {
- type: Number,
- default: 50,
- validator(val: number) {
- return val >= 0;
- },
- },
- parentW: {
- type: Number,
- default: 0,
- validator(val: number) {
- return val >= 0;
- },
- },
- parentH: {
- type: Number,
- default: 0,
- validator(val: number) {
- return val >= 0;
- },
- },
- w: {
- type: [String, Number],
- default: 200,
- validator(val: number) {
- return typeof val === 'string' ? val === 'auto' : val >= 0;
- },
- },
- h: {
- type: [String, Number],
- default: 200,
- validator(val: number) {
- return typeof val === 'string' ? val === 'auto' : val >= 0;
- },
- },
- minw: {
- type: Number,
- default: 50,
- validator(val: number) {
- return val >= 0;
- },
- },
- minh: {
- type: Number,
- default: 50,
- validator(val: number) {
- return val >= 0;
- },
- },
- x: {
- type: Number,
- default: 0,
- validator(val: number) {
- return typeof val === 'number';
- },
- },
- y: {
- type: Number,
- default: 0,
- validator(val: number) {
- return typeof val === 'number';
- },
- },
- z: {
- type: [String, Number],
- default: 'auto',
- validator(val: number) {
- return typeof val === 'string' ? val === 'auto' : val >= 0;
- },
- },
- dragHandle: {
- type: String,
- default: null,
- },
- dragCancel: {
- type: String,
- default: null,
- },
- sticks: {
- type: Array<'bl' | 'bm' | 'br' | 'ml' | 'mr' | 'tl' | 'tm' | 'tr'>,
- default() {
- return ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'];
- },
- },
- axis: {
- type: String,
- default: 'both',
- validator(val: string) {
- return ['both', 'none', 'x', 'y'].includes(val);
- },
- },
- contentClass: {
- type: String,
- required: false,
- default: '',
- },
- });
- const emit = defineEmits([
- 'clicked',
- 'dragging',
- 'dragstop',
- 'resizing',
- 'resizestop',
- 'activated',
- 'deactivated',
- ]);
- const styleMapping = {
- y: {
- t: 'top',
- m: 'marginTop',
- b: 'bottom',
- },
- x: {
- l: 'left',
- m: 'marginLeft',
- r: 'right',
- },
- };
- function addEvents(events: Map<string, (...args: any[]) => void>) {
- events.forEach((cb, eventName) => {
- document.documentElement.addEventListener(eventName, cb);
- });
- }
- function removeEvents(events: Map<string, (...args: any[]) => void>) {
- events.forEach((cb, eventName) => {
- document.documentElement.removeEventListener(eventName, cb);
- });
- }
- const {
- stickSize,
- parentScaleX,
- parentScaleY,
- isActive,
- preventActiveBehavior,
- isDraggable,
- isResizable,
- aspectRatio,
- parentLimitation,
- snapToGrid,
- gridX,
- gridY,
- parentW,
- parentH,
- w,
- h,
- minw,
- minh,
- x,
- y,
- z,
- dragHandle,
- dragCancel,
- sticks,
- axis,
- contentClass,
- } = toRefs(props);
- // states
- const active = ref(false);
- const zIndex = ref<null | number>(null);
- const parentWidth = ref<null | number>(null);
- const parentHeight = ref<null | number>(null);
- const left = ref<null | number>(null);
- const top = ref<null | number>(null);
- const right = ref<null | number>(null);
- const bottom = ref<null | number>(null);
- const aspectFactor = ref<null | number>(null);
- // state end
- const stickDrag = ref(false);
- const bodyDrag = ref(false);
- const dimensionsBeforeMove = ref({
- pointerX: 0,
- pointerY: 0,
- x: 0,
- y: 0,
- w: 0,
- h: 0,
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- width: 0,
- height: 0,
- });
- const limits = ref({
- left: { min: null as null | number, max: null as null | number },
- right: { min: null as null | number, max: null as null | number },
- top: { min: null as null | number, max: null as null | number },
- bottom: { min: null as null | number, max: null as null | number },
- });
- const currentStick = ref<null | string>(null);
- const parentElement = ref<HTMLElement | null>(null);
- const width = computed(() => parentWidth.value! - left.value! - right.value!);
- const height = computed(() => parentHeight.value! - top.value! - bottom.value!);
- const rect = computed(() => ({
- left: Math.round(left.value!),
- top: Math.round(top.value!),
- width: Math.round(width.value),
- height: Math.round(height.value),
- }));
- const saveDimensionsBeforeMove = ({
- pointerX,
- pointerY,
- }: {
- pointerX: number;
- pointerY: number;
- }) => {
- dimensionsBeforeMove.value.pointerX = pointerX;
- dimensionsBeforeMove.value.pointerY = pointerY;
- dimensionsBeforeMove.value.left = left.value as number;
- dimensionsBeforeMove.value.right = right.value as number;
- dimensionsBeforeMove.value.top = top.value as number;
- dimensionsBeforeMove.value.bottom = bottom.value as number;
- dimensionsBeforeMove.value.width = width.value as number;
- dimensionsBeforeMove.value.height = height.value as number;
- aspectFactor.value = width.value / height.value;
- };
- const sideCorrectionByLimit = (
- limit: { max: number; min: number },
- current: number,
- ) => {
- let value = current;
- if (limit.min !== null && current < limit.min) {
- value = limit.min;
- } else if (limit.max !== null && limit.max < current) {
- value = limit.max;
- }
- return value;
- };
- const rectCorrectionByLimit = (rect: {
- newBottom: number;
- newLeft: number;
- newRight: number;
- newTop: number;
- }) => {
- // const { limits } = this;
- let { newRight, newLeft, newBottom, newTop } = rect;
- type RectRange = {
- max: number;
- min: number;
- };
- newLeft = sideCorrectionByLimit(limits.value.left as RectRange, newLeft);
- newRight = sideCorrectionByLimit(limits.value.right as RectRange, newRight);
- newTop = sideCorrectionByLimit(limits.value.top as RectRange, newTop);
- newBottom = sideCorrectionByLimit(
- limits.value.bottom as RectRange,
- newBottom,
- );
- return {
- newLeft,
- newRight,
- newTop,
- newBottom,
- };
- };
- const rectCorrectionByAspectRatio = (rect: {
- newBottom: number;
- newLeft: number;
- newRight: number;
- newTop: number;
- }) => {
- let { newLeft, newRight, newTop, newBottom } = rect;
- // const { parentWidth, parentHeight, currentStick, aspectFactor, dimensionsBeforeMove } = this;
- let newWidth = parentWidth.value! - newLeft - newRight;
- let newHeight = parentHeight.value! - newTop - newBottom;
- if (currentStick.value![1] === 'm') {
- const deltaHeight = newHeight - dimensionsBeforeMove.value.height;
- newLeft -= (deltaHeight * aspectFactor.value!) / 2;
- newRight -= (deltaHeight * aspectFactor.value!) / 2;
- } else if (currentStick.value![0] === 'm') {
- const deltaWidth = newWidth - dimensionsBeforeMove.value.width;
- newTop -= deltaWidth / aspectFactor.value! / 2;
- newBottom -= deltaWidth / aspectFactor.value! / 2;
- } else if (newWidth / newHeight > aspectFactor.value!) {
- newWidth = aspectFactor.value! * newHeight;
- if (currentStick.value![1] === 'l') {
- newLeft = parentWidth.value! - newRight - newWidth;
- } else {
- newRight = parentWidth.value! - newLeft - newWidth;
- }
- } else {
- newHeight = newWidth / aspectFactor.value!;
- if (currentStick.value![0] === 't') {
- newTop = parentHeight.value! - newBottom - newHeight;
- } else {
- newBottom = parentHeight.value! - newTop - newHeight;
- }
- }
- return { newLeft, newRight, newTop, newBottom };
- };
- const stickMove = (delta: { x: number; y: number }) => {
- let newTop = dimensionsBeforeMove.value.top;
- let newBottom = dimensionsBeforeMove.value.bottom;
- let newLeft = dimensionsBeforeMove.value.left;
- let newRight = dimensionsBeforeMove.value.right;
- switch (currentStick.value![0]) {
- case 'b': {
- newBottom = dimensionsBeforeMove.value.bottom + delta.y;
- if (snapToGrid.value) {
- newBottom =
- (parentHeight.value as number) -
- Math.round(
- ((parentHeight.value as number) - newBottom) / gridY.value,
- ) *
- gridY.value;
- }
- break;
- }
- case 't': {
- newTop = dimensionsBeforeMove.value.top - delta.y;
- if (snapToGrid.value) {
- newTop = Math.round(newTop / gridY.value) * gridY.value;
- }
- break;
- }
- default: {
- break;
- }
- }
- switch (currentStick.value![1]) {
- case 'l': {
- newLeft = dimensionsBeforeMove.value.left - delta.x;
- if (snapToGrid.value) {
- newLeft = Math.round(newLeft / gridX.value) * gridX.value;
- }
- break;
- }
- case 'r': {
- newRight = dimensionsBeforeMove.value.right + delta.x;
- if (snapToGrid.value) {
- newRight =
- (parentWidth.value as number) -
- Math.round(((parentWidth.value as number) - newRight) / gridX.value) *
- gridX.value;
- }
- break;
- }
- default: {
- break;
- }
- }
- ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByLimit({
- newLeft,
- newRight,
- newTop,
- newBottom,
- }));
- if (aspectRatio.value) {
- ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByAspectRatio({
- newLeft,
- newRight,
- newTop,
- newBottom,
- }));
- }
- left.value = newLeft;
- right.value = newRight;
- top.value = newTop;
- bottom.value = newBottom;
- emit('resizing', rect.value);
- };
- const stickUp = () => {
- stickDrag.value = false;
- // dimensionsBeforeMove.value = {
- // pointerX: 0,
- // pointerY: 0,
- // x: 0,
- // y: 0,
- // w: 0,
- // h: 0,
- // };
- Object.assign(dimensionsBeforeMove.value, {
- pointerX: 0,
- pointerY: 0,
- x: 0,
- y: 0,
- w: 0,
- h: 0,
- });
- limits.value = {
- left: { min: null, max: null },
- right: { min: null, max: null },
- top: { min: null, max: null },
- bottom: { min: null, max: null },
- };
- emit('resizing', rect.value);
- emit('resizestop', rect.value);
- };
- const calcDragLimitation = () => {
- return {
- left: { min: 0, max: (parentWidth.value as number) - width.value },
- right: { min: 0, max: (parentWidth.value as number) - width.value },
- top: { min: 0, max: (parentHeight.value as number) - height.value },
- bottom: { min: 0, max: (parentHeight.value as number) - height.value },
- };
- };
- const calcResizeLimits = () => {
- // const { aspectFactor, width, height, bottom, top, left, right } = this;
- const parentLim = parentLimitation.value ? 0 : null;
- if (aspectRatio.value) {
- if (minw.value / minh.value > (aspectFactor.value as number)) {
- minh.value = minw.value / (aspectFactor.value as number);
- } else {
- minw.value = ((aspectFactor.value as number) * minh.value) as number;
- }
- }
- const limits = {
- left: {
- min: parentLim,
- max: (left.value as number) + (width.value - minw.value),
- },
- right: {
- min: parentLim,
- max: (right.value as number) + (width.value - minw.value),
- },
- top: {
- min: parentLim,
- max: (top.value as number) + (height.value - minh.value),
- },
- bottom: {
- min: parentLim,
- max: (bottom.value as number) + (height.value - minh.value),
- },
- };
- if (aspectRatio.value) {
- const aspectLimits = {
- left: {
- min:
- left.value! -
- Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,
- max:
- left.value! +
- ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,
- },
- right: {
- min:
- right.value! -
- Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,
- max:
- right.value! +
- ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,
- },
- top: {
- min:
- top.value! -
- (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,
- max:
- top.value! +
- ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,
- },
- bottom: {
- min:
- bottom.value! -
- (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,
- max:
- bottom.value! +
- ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,
- },
- };
- if (currentStick.value![0] === 'm') {
- limits.left = {
- min: Math.max(limits.left.min!, aspectLimits.left.min),
- max: Math.min(limits.left.max, aspectLimits.left.max),
- };
- limits.right = {
- min: Math.max(limits.right.min!, aspectLimits.right.min),
- max: Math.min(limits.right.max, aspectLimits.right.max),
- };
- } else if (currentStick.value![1] === 'm') {
- limits.top = {
- min: Math.max(limits.top.min!, aspectLimits.top.min),
- max: Math.min(limits.top.max, aspectLimits.top.max),
- };
- limits.bottom = {
- min: Math.max(limits.bottom.min!, aspectLimits.bottom.min),
- max: Math.min(limits.bottom.max, aspectLimits.bottom.max),
- };
- }
- }
- return limits;
- };
- const positionStyle = computed(() => ({
- top: `${top.value}px`,
- left: `${left.value}px`,
- zIndex: zIndex.value!,
- }));
- const sizeStyle = computed(() => ({
- width: w.value === 'auto' ? 'auto' : `${width.value}px`,
- height: h.value === 'auto' ? 'auto' : `${height.value}px`,
- }));
- const stickStyles = computed(() => (stick: string) => {
- const stickStyle = {
- width: `${stickSize.value / parentScaleX.value}px`,
- height: `${stickSize.value / parentScaleY.value}px`,
- };
- stickStyle[
- styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width'
- ] = `${stickSize.value / parentScaleX.value / -2}px`;
- stickStyle[
- styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width'
- ] = `${stickSize.value / parentScaleX.value / -2}px`;
- return stickStyle;
- });
- const bodyMove = (delta: { x: number; y: number }) => {
- let newTop = dimensionsBeforeMove.value.top - delta.y;
- let newBottom = dimensionsBeforeMove.value.bottom + delta.y;
- let newLeft = dimensionsBeforeMove.value.left - delta.x;
- let newRight = dimensionsBeforeMove.value.right + delta.x;
- if (snapToGrid.value) {
- let alignTop = true;
- let alignLeft = true;
- let diffT = newTop - Math.floor(newTop / gridY.value) * gridY.value;
- let diffB =
- (parentHeight.value as number) -
- newBottom -
- Math.floor(((parentHeight.value as number) - newBottom) / gridY.value) *
- gridY.value;
- let diffL = newLeft - Math.floor(newLeft / gridX.value) * gridX.value;
- let diffR =
- (parentWidth.value as number) -
- newRight -
- Math.floor(((parentWidth.value as number) - newRight) / gridX.value) *
- gridX.value;
- if (diffT > gridY.value / 2) {
- diffT -= gridY.value;
- }
- if (diffB > gridY.value / 2) {
- diffB -= gridY.value;
- }
- if (diffL > gridX.value / 2) {
- diffL -= gridX.value;
- }
- if (diffR > gridX.value / 2) {
- diffR -= gridX.value;
- }
- if (Math.abs(diffB) < Math.abs(diffT)) {
- alignTop = false;
- }
- if (Math.abs(diffR) < Math.abs(diffL)) {
- alignLeft = false;
- }
- newTop -= alignTop ? diffT : diffB;
- newBottom = (parentHeight.value as number) - height.value - newTop;
- newLeft -= alignLeft ? diffL : diffR;
- newRight = (parentWidth.value as number) - width.value - newLeft;
- }
- ({
- newLeft: left.value,
- newRight: right.value,
- newTop: top.value,
- newBottom: bottom.value,
- } = rectCorrectionByLimit({ newLeft, newRight, newTop, newBottom }));
- emit('dragging', rect.value);
- };
- const bodyUp = () => {
- bodyDrag.value = false;
- emit('dragging', rect.value);
- emit('dragstop', rect.value);
- // dimensionsBeforeMove.value = { pointerX: 0, pointerY: 0, x: 0, y: 0, w: 0, h: 0 };
- Object.assign(dimensionsBeforeMove.value, {
- pointerX: 0,
- pointerY: 0,
- x: 0,
- y: 0,
- w: 0,
- h: 0,
- });
- limits.value = {
- left: { min: null, max: null },
- right: { min: null, max: null },
- top: { min: null, max: null },
- bottom: { min: null, max: null },
- };
- };
- const stickDown = (
- stick: string,
- ev: { pageX: any; pageY: any; touches?: any },
- force = false,
- ) => {
- if ((!isResizable.value || !active.value) && !force) {
- return;
- }
- stickDrag.value = true;
- const pointerX = ev.pageX === undefined ? ev.touches[0].pageX : ev.pageX;
- const pointerY = ev.pageY === undefined ? ev.touches[0].pageY : ev.pageY;
- saveDimensionsBeforeMove({ pointerX, pointerY });
- currentStick.value = stick;
- limits.value = calcResizeLimits();
- };
- const move = (ev: MouseEvent & TouchEvent) => {
- if (!stickDrag.value && !bodyDrag.value) {
- return;
- }
- ev.stopPropagation();
- // touches 兼容性代码
- const pageX = ev.pageX === undefined ? ev.touches![0]!.pageX : ev.pageX;
- const pageY = ev.pageY === undefined ? ev.touches![0]!.pageY : ev.pageY;
- const delta = {
- x: (dimensionsBeforeMove.value.pointerX - pageX) / parentScaleX.value,
- y: (dimensionsBeforeMove.value.pointerY - pageY) / parentScaleY.value,
- };
- if (stickDrag.value) {
- stickMove(delta);
- }
- if (bodyDrag.value) {
- switch (axis.value) {
- case 'none': {
- return;
- }
- case 'x': {
- delta.y = 0;
- break;
- }
- case 'y': {
- delta.x = 0;
- break;
- }
- // No default
- }
- bodyMove(delta);
- }
- };
- const up = () => {
- if (stickDrag.value) {
- stickUp();
- } else if (bodyDrag.value) {
- bodyUp();
- }
- };
- const deselect = () => {
- if (preventActiveBehavior.value) {
- return;
- }
- active.value = false;
- };
- const domEvents = ref(
- new Map([
- ['mousedown', deselect],
- ['mouseleave', up],
- ['mousemove', move],
- ['mouseup', up],
- ['touchcancel', up],
- ['touchend', up],
- ['touchmove', move],
- ['touchstart', up],
- ]),
- );
- const container = ref<HTMLDivElement>();
- onMounted(() => {
- const currentInstance = getCurrentInstance();
- const $el = currentInstance?.vnode.el as HTMLElement;
- parentElement.value = $el?.parentNode as HTMLElement;
- parentWidth.value = parentW.value ?? parentElement.value?.clientWidth;
- parentHeight.value = parentH.value ?? parentElement.value?.clientHeight;
- left.value = x.value;
- top.value = y.value;
- right.value = (parentWidth.value -
- (w.value === 'auto' ? container.value!.scrollWidth : (w.value as number)) -
- left.value) as number;
- bottom.value = (parentHeight.value -
- (h.value === 'auto' ? container.value!.scrollHeight : (h.value as number)) -
- top.value) as number;
- addEvents(domEvents.value);
- if (dragHandle.value) {
- [...($el?.querySelectorAll(dragHandle.value) || [])].forEach(
- (dragHandle) => {
- (dragHandle as HTMLElement).dataset.dragHandle = String(
- currentInstance?.uid,
- );
- },
- );
- }
- if (dragCancel.value) {
- [...($el?.querySelectorAll(dragCancel.value) || [])].forEach(
- (cancelHandle) => {
- (cancelHandle as HTMLElement).dataset.dragCancel = String(
- currentInstance?.uid,
- );
- },
- );
- }
- });
- onBeforeUnmount(() => {
- removeEvents(domEvents.value);
- });
- const bodyDown = (ev: MouseEvent & TouchEvent) => {
- const { target, button } = ev;
- if (!preventActiveBehavior.value) {
- active.value = true;
- }
- if (button && button !== 0) {
- return;
- }
- emit('clicked', ev);
- if (!active.value) {
- return;
- }
- if (
- dragHandle.value &&
- (target! as HTMLElement).dataset.dragHandle !==
- getCurrentInstance()?.uid.toString()
- ) {
- return;
- }
- if (
- dragCancel.value &&
- (target! as HTMLElement).dataset.dragCancel ===
- getCurrentInstance()?.uid.toString()
- ) {
- return;
- }
- if (ev.stopPropagation !== undefined) {
- ev.stopPropagation();
- }
- if (ev.preventDefault !== undefined) {
- ev.preventDefault();
- }
- if (isDraggable.value) {
- bodyDrag.value = true;
- }
- const pointerX = ev.pageX === undefined ? ev.touches[0]!.pageX : ev.pageX;
- const pointerY = ev.pageY === undefined ? ev.touches[0]!.pageY : ev.pageY;
- saveDimensionsBeforeMove({ pointerX, pointerY });
- if (parentLimitation.value) {
- limits.value = calcDragLimitation();
- }
- };
- watch(
- () => active.value,
- (isActive) => {
- if (isActive) {
- emit('activated');
- } else {
- emit('deactivated');
- }
- },
- );
- watch(
- () => isActive.value,
- (val) => {
- active.value = val;
- },
- { immediate: true },
- );
- watch(
- () => z.value,
- (val) => {
- if ((val as number) >= 0 || val === 'auto') {
- zIndex.value = val as number;
- }
- },
- { immediate: true },
- );
- watch(
- () => x.value,
- (newVal, oldVal) => {
- if (stickDrag.value || bodyDrag.value || newVal === left.value) {
- return;
- }
- const delta = oldVal - newVal;
- bodyDown({ pageX: left.value!, pageY: top.value! } as MouseEvent &
- TouchEvent);
- bodyMove({ x: delta, y: 0 });
- nextTick(() => {
- bodyUp();
- });
- },
- );
- watch(
- () => y.value,
- (newVal, oldVal) => {
- if (stickDrag.value || bodyDrag.value || newVal === top.value) {
- return;
- }
- const delta = oldVal - newVal;
- bodyDown({ pageX: left.value, pageY: top.value } as MouseEvent &
- TouchEvent);
- bodyMove({ x: 0, y: delta });
- nextTick(() => {
- bodyUp();
- });
- },
- );
- watch(
- () => w.value,
- (newVal, oldVal) => {
- if (stickDrag.value || bodyDrag.value || newVal === width.value) {
- return;
- }
- const stick = 'mr';
- const delta = (oldVal as number) - (newVal as number);
- stickDown(
- stick,
- { pageX: right.value, pageY: top.value! + height.value / 2 },
- true,
- );
- stickMove({ x: delta, y: 0 });
- nextTick(() => {
- stickUp();
- });
- },
- );
- watch(
- () => h.value,
- (newVal, oldVal) => {
- if (stickDrag.value || bodyDrag.value || newVal === height.value) {
- return;
- }
- const stick = 'bm';
- const delta = (oldVal as number) - (newVal as number);
- stickDown(
- stick,
- { pageX: left.value! + width.value / 2, pageY: bottom.value },
- true,
- );
- stickMove({ x: 0, y: delta });
- nextTick(() => {
- stickUp();
- });
- },
- );
- watch(
- () => parentW.value,
- (val) => {
- right.value = val - width.value - left.value!;
- parentWidth.value = val;
- },
- );
- watch(
- () => parentH.value,
- (val) => {
- bottom.value = val - height.value - top.value!;
- parentHeight.value = val;
- },
- );
- </script>
- <template>
- <div
- :class="`${active || isActive ? 'active' : 'inactive'} ${contentClass ? contentClass : ''}`"
- :style="positionStyle"
- class="resize"
- @mousedown="bodyDown($event as TouchEvent & MouseEvent)"
- @touchend="up"
- @touchstart="bodyDown($event as TouchEvent & MouseEvent)"
- >
- <div ref="container" :style="sizeStyle" class="content-container">
- <slot></slot>
- </div>
- <div
- v-for="(stick, index) of sticks"
- :key="index"
- :class="[`resize-stick-${stick}`, isResizable ? '' : 'not-resizable']"
- :style="stickStyles(stick)"
- class="resize-stick"
- @mousedown.stop.prevent="
- stickDown(stick, $event as TouchEvent & MouseEvent)
- "
- @touchstart.stop.prevent="
- stickDown(stick, $event as TouchEvent & MouseEvent)
- "
- ></div>
- </div>
- </template>
- <style lang="css" scoped>
- .resize {
- position: absolute;
- box-sizing: border-box;
- }
- .resize.active::before {
- position: absolute;
- top: 0;
- left: 0;
- box-sizing: border-box;
- width: 100%;
- height: 100%;
- content: '';
- outline: 1px dashed #d6d6d6;
- }
- .resize-stick {
- position: absolute;
- box-sizing: border-box;
- font-size: 1px;
- background: #fff;
- border: 1px solid #6c6c6c;
- box-shadow: 0 0 2px #bbb;
- }
- .inactive .resize-stick {
- display: none;
- }
- .resize-stick-tl,
- .resize-stick-br {
- cursor: nwse-resize;
- }
- .resize-stick-tm,
- .resize-stick-bm {
- left: 50%;
- cursor: ns-resize;
- }
- .resize-stick-tr,
- .resize-stick-bl {
- cursor: nesw-resize;
- }
- .resize-stick-ml,
- .resize-stick-mr {
- top: 50%;
- cursor: ew-resize;
- }
- .resize-stick.not-resizable {
- display: none;
- }
- .content-container {
- position: relative;
- display: block;
- }
- </style>
|