一路繁花似锦绣前程
失败的越多,成功才越有价值

导航

 
<template>
  <div ref="crtContainerRef" class="crt-container">
    <div
      ref="crtContainerImgContainerRef"
      class="crt-container__img-container"
      :style="{
        left: `${positionInfo.x}px`,
        top: `${positionInfo.y}px`,
      }"
      @mousedown="handleMousedown"
      @mousemove="handleMousemove"
      @mouseup="handleMoveStop"
      @mouseleave="handleMoveStop"
      @mousewheel="handleMousewhell"
    >
      <img
        class="crt-container__img"
        :style="{ zoom: String(positionInfo.zoom) }"
        :src="companyImg"
        alt=""
        @load="handleLoad"
      />
      <img
        v-for="(item, index) of deviceList"
        :key="index"
        :id="item.name"
        :style="{ left: `${item.x}%`, top: `${item.y}%` }"
        class="crt-container__icon"
        :src="item.image"
        alt=""
        @click="emit('handleIconClick', item)"
        @mousewheel.stop="() => {}"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits, defineExpose } from "vue";

defineProps({
  deviceList: {
    type: Array,
    default: () => [],
  },
  companyImg: {
    type: String,
    default: "",
  },
});
const emit = defineEmits(["handleIconClick"]);

const positionInfo = ref({
  move: false,
  x: 0,
  y: 0,
  w: 0,
  h: 0,
  zoom: 1,
  clientX: 0,
  clientY: 0,
});
const crtContainerImgContainerRef = ref(null);
const handleLoad = () => {
  positionInfo.value.w = crtContainerImgContainerRef.value.offsetWidth;
  positionInfo.value.h = crtContainerImgContainerRef.value.offsetHeight;
};
const handleMousewhell = (ev) => {
  if (ev.deltaY < 0) {
    positionInfo.value.zoom += 0.02;
    if (Number(positionInfo.value.zoom.toFixed(2)) > 1) {
      positionInfo.value.zoom = 1;
    } else {
      positionInfo.value.x -=
        (ev.offsetX / crtContainerImgContainerRef.value.offsetWidth) *
        (positionInfo.value.w * 0.02);
      positionInfo.value.y -=
        (ev.offsetY / crtContainerImgContainerRef.value.offsetHeight) *
        (positionInfo.value.h * 0.02);
    }
  } else {
    positionInfo.value.zoom -= 0.02;
    if (Number(positionInfo.value.zoom.toFixed(2)) < 0.8) {
      positionInfo.value.zoom = 0.8;
    } else {
      positionInfo.value.x +=
        (ev.offsetX / crtContainerImgContainerRef.value.offsetWidth) *
        (positionInfo.value.w * 0.02);
      positionInfo.value.y +=
        (ev.offsetY / crtContainerImgContainerRef.value.offsetHeight) *
        (positionInfo.value.h * 0.02);
    }
  }
};
const handleMousedown = (ev) => {
  ev.preventDefault();
  positionInfo.value.move = true;
  positionInfo.value.x = crtContainerImgContainerRef.value.offsetLeft;
  positionInfo.value.y = crtContainerImgContainerRef.value.offsetTop;
  positionInfo.value.clientX = ev.clientX;
  positionInfo.value.clientY = ev.clientY;
};
const handleMousemove = (ev) => {
  if (positionInfo.value.move) {
    positionInfo.value.x += ev.clientX - positionInfo.value.clientX;
    positionInfo.value.y += ev.clientY - positionInfo.value.clientY;
    positionInfo.value.clientX = ev.clientX;
    positionInfo.value.clientY = ev.clientY;
  }
};
const handleMoveStop = () => {
  positionInfo.value.move = false;
};

const crtContainerRef = ref(null);
const handleIconCenter = (name) => {
  const el = document.getElementById(name);
  positionInfo.value.x = -el.offsetLeft + crtContainerRef.value.offsetWidth / 2;
  positionInfo.value.y = -el.offsetTop + crtContainerRef.value.offsetHeight / 2;
};

defineExpose({
  handleIconCenter,
});
</script>

<style scoped lang="scss">
.crt-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}

.crt-container__img-container {
  cursor: grab;
  position: absolute;
  width: fit-content;
}

.crt-container__img-container:active {
  cursor: grabbing;
}

.crt-container__img {
  display: block;
}

.crt-container__icon {
  position: absolute;
  width: 40px;
  height: 40px;
  transform: translate(-50%, -50%);
  cursor: pointer;
}
</style>
posted on 2025-04-15 02:24  一路繁花似锦绣前程  阅读(18)  评论(0)    收藏  举报