<template>
  <div class="drag-box">
    <!-- <div
      ref="DragBox"
      :class="[DefaultClassName, 'drag']"
      :style="{
        backgroundImage: `url(${img})`,
      }"
    >
      <CustomContextMenu :el="DragBox" @change="MenuChange"></CustomContextMenu>
    </div> -->
    <div ref="DragBox" :class="[DefaultClassName, 'drag']">
      <img class="show-img" @dragstart.prevent :src="img" />
    </div>
    <CustomContextMenu :el="DragBox" @change="MenuChange"></CustomContextMenu>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import CustomContextMenu from '@/components/custom/ContextMenu.vue';
const props = defineProps<{
  id: string;
  img: string;
}>();
const emit = defineEmits(['delete']);
// 拖拽元素
const DragBox = ref();
// 默认类名
const DefaultClassName = ref('custom-drag-img' + props.id);
const MenuChange = (item: any) => {
  if (item.value == 'delete') {
    emit('delete', item, props.id);
  }
};
class Drag {
  constructor(
    target,
    options = { limit: true, drag: true, zoom: true, minWidth: 0, minHeight: 0 }
  ) {
    this.target = target;
    this.options = options;
    this.init();
  }
  // 初始化
  init() {
    this.target.style.position = 'relative';
    this.getBoundary();
    if (this.options.drag) {
      this.drag();
    }
    if (this.options.zoom) {
      this.addHorn();
      this.addBorder();
      this.leftZoom();
      this.rightZoom();
      this.topZoom();
      this.bottomZoom();
      this.leftTopZoom();
      this.leftBottomZoom();
      this.rightTopZoom();
      this.rightBottomZoom();
    }
  }
  // 获取父元素的宽高
  getBoundary() {
    this.maxWidth = this.target.parentNode.parentNode.clientWidth;
    this.maxHeight = this.target.parentNode.parentNode.clientHeight;
  }
  // 获取自身起始信息
  getInfo(e) {
    this.width = this.target.clientWidth;
    this.height = this.target.clientHeight;
    let translateStr = this.target.style.transform;
    if (translateStr) {
      const reg = /\d+/g;
      let translateArr = translateStr.match(reg);
      this.tx = Number(translateArr[0]);
      this.ty = Number(translateArr[1]);
    } else {
      this.tx = 0;
      this.ty = 0;
    }
    this.startX = e.clientX;
    this.startY = e.clientY;
  }
  // 拖动实现
  drag() {
    this.target.addEventListener('mousedown', (e) => {
      this.getInfo(e);
      document.onmousemove = (e) => {
        if (this.options.limit) {
          this.distanceX = Math.max(
            0,
            Math.min(
              this.tx + e.clientX - this.startX,
              this.maxWidth - this.width
            )
          );
          this.distanceY = Math.max(
            0,
            Math.min(
              this.ty + e.clientY - this.startY,
              this.maxHeight - this.height
            )
          );
        } else {
          this.distanceX = this.tx + e.clientX - this.startX;
          this.distanceY = this.ty + e.clientY - this.startY;
        }
        this.target.style.transform = `translate(${this.distanceX}px, ${this.distanceY}px)`;
      };
      document.onmouseup = () => {
        document.onmousemove = null;
      };
    });
  }
  // 添加四个角
  addHorn() {
    this.leftTop = document.createElement('div');
    this.rightTop = document.createElement('div');
    this.leftBottom = document.createElement('div');
    this.rightBottom = document.createElement('div');
    this.leftTop.className = 'horn leftTop';
    this.rightTop.className = 'horn rightTop';
    this.leftBottom.className = 'horn leftBottom';
    this.rightBottom.className = 'horn rightBottom';
    this.target.append(this.leftTop);
    this.target.append(this.rightTop);
    this.target.append(this.leftBottom);
    this.target.append(this.rightBottom);
  }
  // 添加四条边
  addBorder() {
    this.left = document.createElement('div');
    this.right = document.createElement('div');
    this._top = document.createElement('div');
    this.bottom = document.createElement('div');
    this.left.className = 'vertical left';
    this.right.className = 'vertical right';
    this._top.className = 'horizontal top';
    this.bottom.className = 'horizontal bottom';
    this.target.append(this.left);
    this.target.append(this.right);
    this.target.append(this._top);
    this.target.append(this.bottom);
  }
  // 缩放实现
  zoom(el: any, direction: any) {
    el.addEventListener('mousedown', (e) => {
      e.stopPropagation();
      this.getInfo(e);
      document.onmousemove = (e) => {
        switch (direction) {
          case 'left':
            this.leftInfo(e);
            break;
          case 'right':
            this.rightInfo(e);
            break;
          case 'top':
            this.topInfo(e);
            break;
          case 'bottom':
            this.bottomInfo(e);
            break;
          case 'leftTop':
            this.leftTopInfo(e);
            break;
          case 'leftBottom':
            this.leftBottomInfo(e);
            break;
          case 'rightTop':
            this.rightTopInfo(e);
            break;
          case 'rightBottom':
            this.rightBottomInfo(e);
            break;
        }
        // 这里不能直接使用对this.newWidth隐式类型转换来判断，因为this.newWidth===0时，会使用this.width
        let width = this.newWidth !== undefined ? this.newWidth : this.width;
        let height =
          this.newHeight !== undefined ? this.newHeight : this.height;
        let translateX =
          this.distanceX !== undefined ? this.distanceX : this.tx;
        let translateY =
          this.distanceY !== undefined ? this.distanceY : this.ty;
        this.target.style.width = `${width}px`;
        this.target.style.height = `${height}px`;
        this.target.style.transform = `translate(${translateX}px, ${translateY}px)`;
      };
      document.onmouseup = () => {
        document.onmousemove = null;
      };
    });
  }
  // 获取缩放时宽高、translate等参数的值
  leftInfo(e: any) {
    this.newWidth = this.width - (e.clientX - this.startX);
    this.distanceX = this.tx + (e.clientX - this.startX);
    if (this.options.limit) {
      this.newWidth = Math.max(
        this.options.minWidth,
        Math.min(this.newWidth, this.width + this.tx)
      );
      this.distanceX = Math.max(
        0,
        Math.min(this.distanceX, this.width + this.tx - this.options.minWidth)
      );
    }
  }
  rightInfo(e: any) {
    this.newWidth = this.width + (e.clientX - this.startX);
    if (this.options.limit) {
      this.newWidth = Math.max(
        this.options.minWidth,
        Math.min(this.newWidth, this.maxWidth - this.tx)
      );
    }
  }
  topInfo(e: any) {
    this.newHeight = this.height - (e.clientY - this.startY);
    this.distanceY = this.ty + (e.clientY - this.startY);
    if (this.options.limit) {
      this.newHeight = Math.max(
        this.options.minHeight,
        Math.min(this.newHeight, this.height + this.ty)
      );
      this.distanceY = Math.max(
        0,
        Math.min(this.distanceY, this.height + this.ty - this.options.minHeight)
      );
    }
  }
  bottomInfo(e: any) {
    this.newHeight = this.height + (e.clientY - this.startY);
    if (this.options.limit) {
      this.newHeight = Math.max(
        this.options.minHeight,
        Math.min(this.newHeight, this.maxHeight - this.ty)
      );
    }
  }
  leftTopInfo(e) {
    this.leftInfo(e);
    this.topInfo(e);
  }
  leftBottomInfo(e) {
    this.leftInfo(e);
    this.bottomInfo(e);
  }
  rightTopInfo(e) {
    this.rightInfo(e);
    this.topInfo(e);
  }
  rightBottomInfo(e) {
    this.rightInfo(e);
    this.bottomInfo(e);
  }
  leftZoom() {
    this.zoom(this.left, 'left');
  }
  rightZoom() {
    this.zoom(this.right, 'right');
  }
  topZoom() {
    this.zoom(this._top, 'top');
  }
  bottomZoom() {
    this.zoom(this.bottom, 'bottom');
  }
  leftTopZoom() {
    this.zoom(this.leftTop, 'leftTop');
  }
  leftBottomZoom() {
    this.zoom(this.leftBottom, 'leftBottom');
  }
  rightTopZoom() {
    this.zoom(this.rightTop, 'rightTop');
  }
  rightBottomZoom() {
    this.zoom(this.rightBottom, 'rightBottom');
  }
}

onMounted(() => {
  let dragEl = document.querySelector(`.${DefaultClassName.value}`);
  if (dragEl) {
    new Drag(dragEl);
  }
});
</script>

<style lang="less">
.drag-box {
  position: absolute;
  top: 0;
  left: 0;
  .show-img {
    width: 100%;
    height: 100%;
    user-select: none;
  }
}
.drag {
  height: 100px;
  width: 100px;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  -moz-background-size: 100% 100%;
  border: 1px dashed transparent;
  cursor: all-scroll;
  &:hover {
    border-color: #ddd;
  }
  .horn {
    width: 14px;
    height: 14px;
    position: absolute;
  }

  .vertical {
    width: 10px;
    height: calc(100% - 14px);
    margin: 7px 0px;
    position: absolute;
    cursor: col-resize;
  }
  .horizontal {
    width: calc(100% - 14px);
    height: 10px;
    margin: 0px 7px;
    position: absolute;
    cursor: row-resize;
  }
  .top {
    top: -5px;
    left: 0;
  }
  .left {
    top: 0;
    left: -5px;
  }

  .bottom {
    left: 0;
    bottom: -5px;
  }

  .right {
    top: 0;
    right: -5px;
  }
  .leftTop {
    cursor: nw-resize;
    left: -7px;
    top: -7px;
  }

  .rightTop {
    cursor: ne-resize;
    right: -7px;
    top: -7px;
  }

  .leftBottom {
    cursor: sw-resize;
    bottom: -7px;
    left: -7px;
  }

  .rightBottom {
    cursor: se-resize;
    right: -7px;
    bottom: -7px;
  }
}
</style>
