|
|
@@ -0,0 +1,606 @@
|
|
|
+<template>
|
|
|
+
|
|
|
+ <div class="main_container" ref="mainContainer" v-loading="loading" element-loading-text="图片加载中……" element-loading-spinner="el-icon-loading" element-loading-background="#ffffff" @wheel="onWheel">
|
|
|
+
|
|
|
+ <canvas ref="paperCanvas" class="paper_canvas" :width="canvasInfo.width" :height="canvasInfo.height" @mousedown="startDrag" @mousemove="onDrag" @mouseup="stopDrag"></canvas>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
|
|
+import { throttle } from 'lodash';
|
|
|
+
|
|
|
+// props定义
|
|
|
+const props = defineProps({
|
|
|
+ paperType: {
|
|
|
+ type: String,
|
|
|
+ default: 'student'
|
|
|
+ },//类型 模板 还是学生
|
|
|
+
|
|
|
+ usedCardType: {
|
|
|
+ type: [Number, String],
|
|
|
+ default: 1
|
|
|
+ },//系统卡 还是三方卡 0-未制卡 1-系统卡 2-三方卡
|
|
|
+
|
|
|
+ paperImgUrl: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },//试卷地址
|
|
|
+
|
|
|
+ positionList: {
|
|
|
+ type: Array,
|
|
|
+ default: () => []
|
|
|
+ }//定位点坐标列表 {x:0,y:0}
|
|
|
+});
|
|
|
+
|
|
|
+// emit定义
|
|
|
+const emit = defineEmits(['GetCutPosition']);
|
|
|
+
|
|
|
+// 鼠标拖动相关
|
|
|
+const startX = ref(0);//鼠标按下时的初始位置x坐标
|
|
|
+const startY = ref(0);//鼠标按下时的初始位置y坐标
|
|
|
+const currentX = ref(0);//试卷的位置 相对于canvas
|
|
|
+const currentY = ref(0);//试卷的位置 相对于canvas
|
|
|
+const scale = ref(1);//画布缩放倍数
|
|
|
+const isDragging = ref(false);
|
|
|
+const loading = ref(false);//加载loading
|
|
|
+
|
|
|
+// 图片对象
|
|
|
+const image = new Image();
|
|
|
+
|
|
|
+// 试卷显示的大小
|
|
|
+const paperImgInfo = reactive({
|
|
|
+ width: 0,
|
|
|
+ height: 0
|
|
|
+});
|
|
|
+
|
|
|
+// 画布的大小
|
|
|
+const canvasInfo = reactive({
|
|
|
+ width: 1240,
|
|
|
+ height: 1754
|
|
|
+});
|
|
|
+
|
|
|
+// 显示的图片的大小
|
|
|
+const imageSize = reactive({
|
|
|
+ width: 0,
|
|
|
+ height: 0
|
|
|
+});
|
|
|
+
|
|
|
+// canvas相关
|
|
|
+const paperCanvas = ref(null);//试卷画布
|
|
|
+const paperCtx = ref(null);
|
|
|
+const zoomRate = ref(1);//图片的缩放比例
|
|
|
+
|
|
|
+// 定位点坐标
|
|
|
+const point1 = reactive({
|
|
|
+ x: 30,
|
|
|
+ y: 25
|
|
|
+});//定位一坐标点
|
|
|
+
|
|
|
+const point2 = reactive({
|
|
|
+ x: 0,
|
|
|
+ y: 0
|
|
|
+});//定位2的坐标点
|
|
|
+
|
|
|
+const point3 = reactive({
|
|
|
+ x: 33,
|
|
|
+ y: 44
|
|
|
+});//定位3的坐标
|
|
|
+
|
|
|
+const point4 = reactive({
|
|
|
+ x: 0,
|
|
|
+ y: 0
|
|
|
+});//定位4的坐标
|
|
|
+
|
|
|
+// 定位点拖动状态
|
|
|
+const isDragging1 = ref(false);//是否可以拖动定位1
|
|
|
+const isDragging2 = ref(false);//是否可以拖动定位2
|
|
|
+const isDragging3 = ref(false);//是否可以拖动定位3
|
|
|
+const isDragging4 = ref(false);//是否可以拖动定位4
|
|
|
+
|
|
|
+// 旋转相关
|
|
|
+const rotationAngle = ref(0);//初始旋转角度
|
|
|
+const rotate = ref(0);//选择记录 0 未旋转 1 顺时针90 2 顺时针180 3 顺时针270
|
|
|
+const iconWidth = ref(40);//图标宽度
|
|
|
+const iconHeight = ref(40);//图标高度
|
|
|
+
|
|
|
+// 重绘控制
|
|
|
+const redrawPending = ref(false);//用与防止多次请求重绘画布
|
|
|
+const animationId = ref(null);
|
|
|
+
|
|
|
+// 容器引用
|
|
|
+const mainContainer = ref(null);
|
|
|
+
|
|
|
+// 监听试卷地址变化
|
|
|
+watch(() => props.paperImgUrl, () => {
|
|
|
+ console.log("地址变化了", props.paperImgUrl);
|
|
|
+ console.log("打印positionList", props.positionList);
|
|
|
+ InitCanvasData();//初始化数据
|
|
|
+});
|
|
|
+
|
|
|
+// 监听定位点坐标变化
|
|
|
+watch(() => props.positionList, (newVal) => {
|
|
|
+ console.log("坐标变化了", props.positionList);
|
|
|
+ // 只在有图片且画布已初始化时才更新标注位置
|
|
|
+ if (image.src && paperCtx.value && newVal && newVal.length > 0) {
|
|
|
+ if (props.usedCardType == 1) {
|
|
|
+ // 系统卡:更新4个定位点
|
|
|
+ if (newVal.length >= 4) {
|
|
|
+ Object.assign(point1, newVal[0]);
|
|
|
+ Object.assign(point2, newVal[1]);
|
|
|
+ Object.assign(point3, newVal[2]);
|
|
|
+ Object.assign(point4, newVal[3]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 三方卡:更新2个定位点
|
|
|
+ if (newVal.length >= 2) {
|
|
|
+ Object.assign(point1, newVal[0]);
|
|
|
+ Object.assign(point3, newVal[2]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 只重绘定位点,不重新加载图片
|
|
|
+ RequestRedraw();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 组件挂载
|
|
|
+onMounted(() => {
|
|
|
+ InitCanvasData();//初始化数据
|
|
|
+});
|
|
|
+
|
|
|
+// 组件卸载前
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ // 取消未完成的动画请求
|
|
|
+ if (animationId.value) {
|
|
|
+ cancelAnimationFrame(animationId.value);
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 适应屏幕
|
|
|
+const FitScreen = () => {
|
|
|
+ InitCanvasData();//初始化数据
|
|
|
+};
|
|
|
+
|
|
|
+// 加载图片
|
|
|
+const LoadImage = () => {
|
|
|
+ image.src = props.paperImgUrl;
|
|
|
+ image.crossOrigin = "Anonymous";//设置跨域属性 不设置跨域 导出的图片没有图片
|
|
|
+ image.onload = () => {
|
|
|
+ DrawImage();
|
|
|
+ DrawPosition();//加载定位点坐标
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// 初始画布数据加载
|
|
|
+const InitCanvasData = () => {
|
|
|
+ let { width, height } = mainContainer.value.getBoundingClientRect();
|
|
|
+ loading.value = true;
|
|
|
+ console.log("打印容器宽高", width, height);
|
|
|
+ rotationAngle.value = 0;
|
|
|
+ canvasInfo.width = width;
|
|
|
+ canvasInfo.height = height;
|
|
|
+ paperCanvas.value = mainContainer.value.querySelector('.paper_canvas');
|
|
|
+ paperCtx.value = paperCanvas.value.getContext('2d');
|
|
|
+ console.log("打印this.paperCtx", paperCtx.value);
|
|
|
+ image.src = props.paperImgUrl;
|
|
|
+
|
|
|
+ image.crossOrigin = "Anonymous";//设置跨域属性 不设置跨域 导出的图片没有图片
|
|
|
+ image.onload = () => {
|
|
|
+ // 使用 nextTick 确保 DOM 更新后再执行计算
|
|
|
+ nextTick(() => {
|
|
|
+ console.log("图片加载成功", image.width, image.height);
|
|
|
+
|
|
|
+ // 优化缩放比例计算逻辑
|
|
|
+ const containerPadding = 20; // 容器内边距
|
|
|
+ let widthScale = (canvasInfo.width - containerPadding) / image.width;
|
|
|
+ let heightScale = (canvasInfo.height - containerPadding) / image.height;
|
|
|
+
|
|
|
+ // 选择较小的缩放比例以确保图片完整显示
|
|
|
+ zoomRate.value = Math.min(widthScale, heightScale);
|
|
|
+ scale.value = 1;//初始默认1
|
|
|
+ console.log("打印初始缩放比例是", zoomRate.value);
|
|
|
+
|
|
|
+ // 计算图片显示的宽高
|
|
|
+ paperImgInfo.width = image.width * zoomRate.value;
|
|
|
+ paperImgInfo.height = image.height * zoomRate.value;
|
|
|
+ console.log("打印图片的地址", props.paperImgUrl);
|
|
|
+
|
|
|
+ // 计算图片的位置
|
|
|
+ currentX.value = (canvasInfo.width - paperImgInfo.width * scale.value) / 2;
|
|
|
+ currentY.value = (canvasInfo.height - paperImgInfo.height * scale.value) / 2;
|
|
|
+
|
|
|
+ // 坐标位置 左上 右上 右下 左下 黑块的坐标 30 25 黑块的宽高 25 15
|
|
|
+ if (props.usedCardType == 1) {
|
|
|
+ console.log("系统卡,定位点", props.positionList);
|
|
|
+ if (props.positionList.length > 0) {
|
|
|
+ // 系统卡
|
|
|
+ Object.assign(point1, props.positionList[0]);//左上
|
|
|
+ Object.assign(point2, props.positionList[1]);//右上
|
|
|
+ Object.assign(point3, props.positionList[2]);//右下
|
|
|
+ Object.assign(point4, props.positionList[3]);//左下
|
|
|
+ } else {
|
|
|
+ // 系统卡默认坐标
|
|
|
+ Object.assign(point1, { x: 30, y: 25 });//左上
|
|
|
+ Object.assign(point2, { x: image.width - 30, y: 25 });//右上
|
|
|
+ Object.assign(point3, { x: image.width - 30, y: image.height - 25 });//右下
|
|
|
+ Object.assign(point4, { x: 30, y: image.height - 25 });//左下
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log("三方卡,定位点为空,使用默认坐标");
|
|
|
+ // 三方卡
|
|
|
+ if (props.positionList.length > 0) {
|
|
|
+ Object.assign(point1, props.positionList[0]);//左上
|
|
|
+ Object.assign(point2, props.positionList[1]);//右上
|
|
|
+ Object.assign(point3, props.positionList[2]);//右下
|
|
|
+ Object.assign(point4, props.positionList[3]);//左下
|
|
|
+ } else {
|
|
|
+ // 三方卡默认坐标
|
|
|
+ Object.assign(point1, { x: 30, y: 25 });//左上
|
|
|
+ Object.assign(point2, { x: image.width - 30, y: 25 });//右上
|
|
|
+ Object.assign(point3, { x: image.width - 30, y: image.height - 25 });//右下
|
|
|
+ Object.assign(point4, { x: 30, y: image.height - 25 });//左下
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ loading.value = false;
|
|
|
+ }, 500);
|
|
|
+
|
|
|
+ // 使用 Promise 确保所有计算完成后再加载图片
|
|
|
+ Promise.resolve().then(() => {
|
|
|
+ LoadImage();
|
|
|
+ }).catch(error => {
|
|
|
+ console.error('加载图片时出错:', error);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ loading.value = false;
|
|
|
+ }, 2500);
|
|
|
+};
|
|
|
+
|
|
|
+// 根据地址获取旋转角度
|
|
|
+const GetRotationFromUrl = (url) => {
|
|
|
+ if (!url) return 0;
|
|
|
+
|
|
|
+ // 匹配 x-oss-process=image/rotate,xxx 格式的旋转参数
|
|
|
+ const rotateRegex = /x-oss-process=image\/rotate,(\d+)/;
|
|
|
+ const match = url.match(rotateRegex);
|
|
|
+
|
|
|
+ if (match && match[1]) {
|
|
|
+ return parseInt(match[1], 10);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+// 判断鼠标位置是否在定位点的图标内
|
|
|
+const CheckPointInIcon = (x, y, point) => {
|
|
|
+ const iconW = iconWidth.value * scale.value;
|
|
|
+ const iconH = iconHeight.value * scale.value;
|
|
|
+ const rect = {
|
|
|
+ left: point.x * zoomRate.value * scale.value + currentX.value - iconW / 2,
|
|
|
+ right: point.x * zoomRate.value * scale.value + currentX.value + iconW / 2,
|
|
|
+ top: point.y * zoomRate.value * scale.value + currentY.value - iconH / 2,
|
|
|
+ bottom: point.y * zoomRate.value * scale.value + currentY.value + iconH / 2,
|
|
|
+ };
|
|
|
+
|
|
|
+ let result = false;
|
|
|
+ if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
|
+ result = true;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+};
|
|
|
+
|
|
|
+// 选择图片 顺时针旋转
|
|
|
+const ClockwiseRotateImage = () => {
|
|
|
+ // 每次点击时增加旋转角度
|
|
|
+ rotationAngle.value += 90;
|
|
|
+ RequestRedraw();//请求重绘
|
|
|
+};
|
|
|
+
|
|
|
+// 逆时针旋转图片
|
|
|
+const AnticlockwiseRotateImage = () => {
|
|
|
+ // 每次点击时增加旋转角度
|
|
|
+ rotationAngle.value -= 90;
|
|
|
+ rotate.value -= 1;
|
|
|
+ RequestRedraw();//请求重绘
|
|
|
+};
|
|
|
+
|
|
|
+// 放大图片
|
|
|
+const ZoomIn = (event) => {
|
|
|
+ // 如果有鼠标事件,则以鼠标位置为中心进行缩放
|
|
|
+ let mouseX, mouseY;
|
|
|
+ if (event) {
|
|
|
+ const rect = mainContainer.value.getBoundingClientRect();
|
|
|
+ mouseX = event.clientX - rect.left;
|
|
|
+ mouseY = event.clientY - rect.top;
|
|
|
+ } else {
|
|
|
+ // 如果没有鼠标事件,默认以图片中心点缩放
|
|
|
+ mouseX = canvasInfo.width / 2;
|
|
|
+ mouseY = canvasInfo.height / 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算鼠标在图片上的相对位置 (0-1之间)
|
|
|
+ const relativeX = (mouseX - currentX.value) / (paperImgInfo.width * scale.value);
|
|
|
+ const relativeY = (mouseY - currentY.value) / (paperImgInfo.height * scale.value);
|
|
|
+
|
|
|
+ // 向上滚动放大
|
|
|
+ const oldScale = scale.value;
|
|
|
+ scale.value *= 1.1;
|
|
|
+ // 确保缩放比例不小于最小值
|
|
|
+ if (scale.value > 2.5) {
|
|
|
+ scale.value = 2.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果确实发生了缩放
|
|
|
+ if (scale.value !== oldScale) {
|
|
|
+ // 根据相对位置调整图片位置,使鼠标位置保持不变
|
|
|
+ currentX.value = mouseX - (relativeX * paperImgInfo.width * scale.value);
|
|
|
+ currentY.value = mouseY - (relativeY * paperImgInfo.height * scale.value);
|
|
|
+ }
|
|
|
+ RequestRedraw();//请求重绘
|
|
|
+};
|
|
|
+
|
|
|
+// 缩小图片
|
|
|
+const ZoomOut = (event) => {
|
|
|
+ // 如果有鼠标事件,则以鼠标位置为中心进行缩放
|
|
|
+ let mouseX, mouseY;
|
|
|
+ if (event) {
|
|
|
+ const rect = mainContainer.value.getBoundingClientRect();
|
|
|
+ mouseX = event.clientX - rect.left;
|
|
|
+ mouseY = event.clientY - rect.top;
|
|
|
+ } else {
|
|
|
+ // 如果没有鼠标事件,默认以图片中心点缩放
|
|
|
+ mouseX = canvasInfo.width / 2;
|
|
|
+ mouseY = canvasInfo.height / 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算鼠标在图片上的相对位置 (0-1之间)
|
|
|
+ const relativeX = (mouseX - currentX.value) / (paperImgInfo.width * scale.value);
|
|
|
+ const relativeY = (mouseY - currentY.value) / (paperImgInfo.height * scale.value);
|
|
|
+
|
|
|
+ // 向下滚动缩小
|
|
|
+ const oldScale = scale.value;
|
|
|
+ scale.value /= 1.1;
|
|
|
+
|
|
|
+ // 确保缩放比例不小于最小值
|
|
|
+ if (scale.value < 0.5) {
|
|
|
+ scale.value = 0.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果确实发生了缩放
|
|
|
+ if (scale.value !== oldScale) {
|
|
|
+ // 根据相对位置调整图片位置,使鼠标位置保持不变
|
|
|
+ currentX.value = mouseX - (relativeX * paperImgInfo.width * scale.value);
|
|
|
+ currentY.value = mouseY - (relativeY * paperImgInfo.height * scale.value);
|
|
|
+ }
|
|
|
+ RequestRedraw();//请求重绘
|
|
|
+};
|
|
|
+
|
|
|
+// 绘制图片
|
|
|
+const DrawImage = () => {
|
|
|
+ // 图片加载完成后在canvas上绘制图片
|
|
|
+ if (image) {
|
|
|
+ // 清除之前绘制的内容
|
|
|
+ paperCtx.value.clearRect(0, 0, canvasInfo.width, canvasInfo.height);
|
|
|
+ paperCtx.value.drawImage(image, currentX.value, currentY.value, paperImgInfo.width * scale.value, paperImgInfo.height * scale.value);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 加载定位图标
|
|
|
+const DrawPosition = () => {
|
|
|
+ let positionImg = new Image();
|
|
|
+ positionImg.src = require('../assets/position_icon.png');
|
|
|
+ positionImg.onload = () => {
|
|
|
+ // 重新计算坐标的位置点
|
|
|
+ const iconW = iconWidth.value * scale.value;
|
|
|
+ const iconH = iconHeight.value * scale.value;
|
|
|
+ let pointlist = [point1, point2, point3, point4];
|
|
|
+
|
|
|
+ if (props.positionList.length > 0) {
|
|
|
+ pointlist = props.positionList;
|
|
|
+ if (props.usedCardType == 1) {
|
|
|
+ // 系统卡
|
|
|
+ pointlist = props.positionList;
|
|
|
+ } else {
|
|
|
+ // 三方卡
|
|
|
+ pointlist = [point1, point3];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (props.usedCardType == 1) {
|
|
|
+ // 系统卡
|
|
|
+ pointlist = [point1, point2, point3, point4];
|
|
|
+ } else {
|
|
|
+ // 三方卡
|
|
|
+ pointlist = [point1, point3];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pointlist.forEach((point) => {
|
|
|
+ // 修改为使用相对于原始图片的px单位坐标
|
|
|
+ const x = currentX.value + point.x * zoomRate.value * scale.value - iconW / 2;
|
|
|
+ const y = currentY.value + point.y * zoomRate.value * scale.value - iconH / 2;
|
|
|
+ paperCtx.value.drawImage(positionImg, x, y, iconW, iconH);
|
|
|
+ });
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// 请求重绘
|
|
|
+const RequestRedraw = (point) => {
|
|
|
+ if (!redrawPending.value) {
|
|
|
+ redrawPending.value = true;
|
|
|
+ animationId.value = requestAnimationFrame(() => {
|
|
|
+ if (point) {
|
|
|
+ LoadImage();//重新加载
|
|
|
+ } else {
|
|
|
+ DrawImage();
|
|
|
+ DrawPosition();
|
|
|
+ }
|
|
|
+ redrawPending.value = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 开始拖动时记录起始位置和偏移量
|
|
|
+const startDrag = (event) => {
|
|
|
+ startX.value = event.clientX - currentX.value;
|
|
|
+ startY.value = event.clientY - currentY.value;
|
|
|
+ const rect = paperCanvas.value.getBoundingClientRect();
|
|
|
+ const mouseX = event.clientX - rect.left;
|
|
|
+ const mouseY = event.clientY - rect.top;
|
|
|
+
|
|
|
+ if (CheckPointInIcon(mouseX, mouseY, point1)) {
|
|
|
+ if (props.paperType == 'template') {
|
|
|
+ return;//模板阻止拖动
|
|
|
+ }
|
|
|
+ event.stopPropagation();//阻止事件冒泡
|
|
|
+ // 判断是否可以拖动
|
|
|
+ isDragging1.value = true;
|
|
|
+ isDragging2.value = false;
|
|
|
+ isDragging3.value = false;
|
|
|
+ isDragging4.value = false;
|
|
|
+ isDragging.value = false;
|
|
|
+ paperCanvas.value.style.cursor = "pointer";
|
|
|
+ } else if (CheckPointInIcon(mouseX, mouseY, point2)) {
|
|
|
+ if (props.paperType == 'template') {
|
|
|
+ return;//模板阻止拖动
|
|
|
+ }
|
|
|
+ event.stopPropagation();//阻止事件冒泡
|
|
|
+ isDragging1.value = false;
|
|
|
+ isDragging2.value = true;
|
|
|
+ isDragging3.value = false;
|
|
|
+ isDragging4.value = false;
|
|
|
+ isDragging.value = false;
|
|
|
+ } else if (CheckPointInIcon(mouseX, mouseY, point3)) {
|
|
|
+ if (props.paperType == 'template') {
|
|
|
+ return;//模板阻止拖动
|
|
|
+ }
|
|
|
+ event.stopPropagation();//阻止事件冒泡
|
|
|
+ isDragging1.value = false;
|
|
|
+ isDragging2.value = false;
|
|
|
+ isDragging3.value = true;
|
|
|
+ isDragging4.value = false;
|
|
|
+ isDragging.value = false;
|
|
|
+ } else if (CheckPointInIcon(mouseX, mouseY, point4)) {
|
|
|
+ if (props.paperType == 'template') {
|
|
|
+ return;//模板阻止拖动
|
|
|
+ }
|
|
|
+ event.stopPropagation();//阻止事件冒泡
|
|
|
+ isDragging1.value = false;
|
|
|
+ isDragging2.value = false;
|
|
|
+ isDragging3.value = false;
|
|
|
+ isDragging4.value = true;
|
|
|
+ isDragging.value = false;
|
|
|
+ } else {
|
|
|
+ isDragging1.value = false;
|
|
|
+ isDragging2.value = false;
|
|
|
+ isDragging3.value = false;
|
|
|
+ isDragging4.value = false;
|
|
|
+ isDragging.value = true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 方法结束时重置拖动状态
|
|
|
+const stopDrag = () => {
|
|
|
+ isDragging.value = false;
|
|
|
+ isDragging1.value = false;
|
|
|
+ isDragging2.value = false;
|
|
|
+ isDragging3.value = false;
|
|
|
+ isDragging4.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+// 拖动过程更新图片位置并重新绘制
|
|
|
+const onDrag = (event) => {
|
|
|
+ if (isDragging.value) {
|
|
|
+ const newX = event.clientX - startX.value;
|
|
|
+ const newY = event.clientY - startY.value;
|
|
|
+ currentX.value = newX;
|
|
|
+ currentY.value = newY;
|
|
|
+ RequestRedraw();//请求重绘
|
|
|
+ }
|
|
|
+
|
|
|
+ const rect = paperCanvas.value.getBoundingClientRect();
|
|
|
+ const mouseX = event.clientX - rect.left;
|
|
|
+ const mouseY = event.clientY - rect.top;
|
|
|
+
|
|
|
+ // 这里需要返回原图的px坐标 定位块中心点的坐标
|
|
|
+ const iconW = iconWidth.value * scale.value;
|
|
|
+ const iconH = iconHeight.value * scale.value;
|
|
|
+
|
|
|
+ const newPoint = {
|
|
|
+ x: Math.round((mouseX - currentX.value) / (zoomRate.value * scale.value)),
|
|
|
+ y: Math.round((mouseY - currentY.value) / (zoomRate.value * scale.value))
|
|
|
+ };
|
|
|
+
|
|
|
+ // 坐标点一
|
|
|
+ if (isDragging1.value) {
|
|
|
+ Object.assign(point1, newPoint);
|
|
|
+ RequestRedraw(point1);//请求重绘
|
|
|
+ let list = [point1, point2, point3, point4];
|
|
|
+ emit("GetCutPosition", list);
|
|
|
+ }
|
|
|
+ if (isDragging2.value) {
|
|
|
+ Object.assign(point2, newPoint);
|
|
|
+ RequestRedraw(point2);//请求重绘
|
|
|
+ let list = [point1, point2, point3, point4];
|
|
|
+ emit("GetCutPosition", list);
|
|
|
+ }
|
|
|
+ if (isDragging3.value) {
|
|
|
+ Object.assign(point3, newPoint);
|
|
|
+ RequestRedraw(point3);//请求重绘
|
|
|
+ let list = [point1, point2, point3, point4];
|
|
|
+ emit("GetCutPosition", list);
|
|
|
+ }
|
|
|
+ if (isDragging4.value) {
|
|
|
+ Object.assign(point4, newPoint);
|
|
|
+ RequestRedraw(point4);//请求重绘
|
|
|
+ let list = [point1, point2, point3, point4];
|
|
|
+ emit("GetCutPosition", list);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 处理鼠标滚轮事件
|
|
|
+const onWheel = throttle(function(event) {
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ // 计算新的缩放比例
|
|
|
+ if (event.deltaY < 0) {
|
|
|
+ // 向上滚动放大
|
|
|
+ ZoomIn(event);
|
|
|
+ } else {
|
|
|
+ ZoomOut(event);
|
|
|
+ }
|
|
|
+}, 100);//节流 100毫秒内最多执行一次
|
|
|
+
|
|
|
+// 监听窗口大小变化,重新计算表格高度 使用节流防止频繁改变窗口大小导致计算量过大而页面卡顿
|
|
|
+const handleResize = throttle(function() {
|
|
|
+ // 窗口变化重新计算canvas的宽高
|
|
|
+ let { width, height } = mainContainer.value.getBoundingClientRect();
|
|
|
+}, 500); // 节流 500 毫秒内最多执行一次
|
|
|
+
|
|
|
+// 暴露方法给父组件
|
|
|
+defineExpose({
|
|
|
+ FitScreen,
|
|
|
+ ClockwiseRotateImage,
|
|
|
+ AnticlockwiseRotateImage
|
|
|
+});
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.main_container
|
|
|
+{
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+#paperCanvas
|
|
|
+{
|
|
|
+ position: absolute;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: transform 0.3s ease-in-out;/* 添加平滑过渡效果 */
|
|
|
+}
|
|
|
+</style>
|