From ed07181a5e048203a8873c811cefad09d333aadc Mon Sep 17 00:00:00 2001 From: sunmeng Date: Wed, 13 Aug 2025 18:14:56 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=89=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/index/gesture-canvas-page.vue | 276 +++++++++++------- pages/index/gesture-handler.js | 120 ++++---- pages/index/transform-canvas.vue | 93 ++++-- .../pages/index/gesture-canvas-page.js.map | 2 +- .../pages/index/gesture-handler.js.map | 2 +- .../pages/index/transform-canvas.js.map | 2 +- unpackage/dist/dev/mp-weixin/common/vendor.js | 2 +- .../pages/index/gesture-canvas-page.js | 149 ++++++---- .../mp-weixin/pages/index/gesture-handler.js | 12 +- .../mp-weixin/pages/index/transform-canvas.js | 54 +++- 10 files changed, 446 insertions(+), 266 deletions(-) diff --git a/pages/index/gesture-canvas-page.vue b/pages/index/gesture-canvas-page.vue index 2833be8..f4661c2 100644 --- a/pages/index/gesture-canvas-page.vue +++ b/pages/index/gesture-canvas-page.vue @@ -21,6 +21,7 @@ :imgUrl="'https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg'" :areaData="currentView === 'area' ? seatAreas : []" :seatData="currentView === 'seat' ? seatPositions : []" + :selectedCodes="selectedCodes" /> @@ -57,7 +58,8 @@ export default { seatAreas: [], // 座位区域数据 currentView:'area', seatPositions: [], // 座位数据 - selectedArea: null // 当前选中分区 + selectedArea: null, // 当前选中分区 + selectedCodes: new Set(), // 存储选中的座位code }; }, @@ -84,9 +86,10 @@ export default { // 计算点击坐标(考虑dpr) const x = (e.detail.x - this.containerRect.left) * dpr; const y = (e.detail.y - this.containerRect.top) * dpr; - + console.log('handleCanvasClick',x,y) if (this.currentView === 'area') { const hitArea = this.$refs.canvasRef.checkHitArea(x, y); + console.log('handleCanvasClick',hitArea) if (hitArea) { uni.showModal({ title: '请确认', @@ -99,7 +102,6 @@ export default { this.currentView = 'seat'; this.loadSeatData(hitArea.areacode) } - console.log(res,'showModa-- success') }, }) } @@ -107,12 +109,32 @@ export default { const hitSeat = this.$refs.canvasRef.checkSeatHit(x, y); if (hitSeat) { console.log('选中座位:', hitSeat); + this.toggleSeatSelection(hitSeat); // 这里可以添加座位选择逻辑 } } }, + toggleSeatSelection(seat) { + if (seat.status !== 1) return; // 只允许选择可用座位 + + if (this.selectedCodes.has(seat.code)) { + this.selectedCodes.delete(seat.code); + } else { + // 限制最多选择4个座位 + if (this.selectedCodes.size < 4) { + this.selectedCodes.add(seat.code); + } else { + uni.showToast({ + title: '最多只能选择4个座位', + icon: 'none' + }); + } + } + this.$refs.canvasRef.redraw(); // 触发重绘 + }, + async getContainerPosition() { // 添加重试机制 let retryCount = 0; @@ -136,9 +158,9 @@ export default { }; return; } - } catch (e) { - console.error('获取容器位置失败:', e); - } + } catch (e) { + console.error('获取容器位置失败:', e); + } // 等待后重试 await new Promise(r => setTimeout(r, 100)); @@ -147,89 +169,111 @@ export default { }, initGestureHandler() { - try { - this.gestureHandler = new GestureHandler(this, this.transformMatrix, { - container: this.containerRect - }); - } catch (e) { - console.error('手势处理器初始化失败:', e); - // 简化降级方案 - this.gestureHandler = { - catchEvent: (event) => { - if (event.touches.length > 0) { - this.gestureStatus = "降级模式"; - this.touchPoints = event.touches.length; - - if (event.type === 'touchmove') { - const firstTouch = event.touches[0]; - const x = firstTouch.clientX - this.containerRect.left; - const y = firstTouch.clientY - this.containerRect.top; - - this.transformMatrix.tx = x; - this.transformMatrix.ty = y; - this.updateCanvas(); - } - } - } - } - } - }, - - // 事件处理 - async handleTouchEvent(event) { - if (!this.gestureHandler || !this.containerRect) { - await this.getContainerPosition(); - this.initGestureHandler(); - if (event.type === 'touchend' || event.type === 'touchcancel') { - this.gestureStatus = '结束'; - this.updateCanvas(); - return; - } - } - - // 记录时间戳 - const currentTime = Date.now(); - - // 更新触点数量 - this.touchPoints = event.touches.length; - - // 修正坐标 - const correctedTouches = Array.from(event.touches).map(touch => { - return { - ...touch, - x: touch.clientX - this.containerRect.left, - y: touch.clientY - this.containerRect.top - }; - }); - - // 创建修正后的事件对象 - const correctedEvent = { - ...event, - touches: correctedTouches, - changedTouches: correctedTouches - }; - - // 传递事件给手势处理器 - this.gestureHandler.catchEvent(correctedEvent); - - // 更新手势状态 - if (event.type === 'touchstart') { - this.gestureStatus = event.touches.length > 1 ? '双指开始' : '单指开始'; - } - else if (event.type === 'touchmove') { - this.gestureStatus = event.touches.length > 1 ? '双指缩放/移动' : '单指移动'; - } - else { - this.gestureStatus = '结束'; - } - - // 限制更新频率 - if (currentTime - this.lastGestureTime > 50) { - this.lastGestureTime = currentTime; - this.updateCanvas(); - } - }, - + try { + this.gestureHandler = new GestureHandler(this, this.transformMatrix, { + container: this.containerRect + }); + console.log( 'initGestureHandler', this.gestureHandler ) + } catch (e) { + console.error('手势处理器初始化失败:', e); + // 简化降级方案 + this.gestureHandler = { + catchEvent: this.createGestureFallback(), + setScale: (scale) => { + this.transformMatrix.scale(scale, scale, this.canvasWidth/2, this.canvasHeight/2); + this.updateCanvas(); + }, + reset: () => { + this.transformMatrix.reset(); + this.updateCanvas(); + } + } + } + }, + + createGestureFallback() { + let isClick = true; + let startPoint = null; + let startTime = null; + let lastPoint = null; + + return (event) => { + const touches = event.touches || []; + + if (touches.length === 1) { + const getPoint = (t) => ({ + x: t.clientX - this.containerRect.left, + y: t.clientY - this.containerRect.top + }); + + const currentPoint = getPoint(touches[0]); + + if (!startPoint) { + startPoint = currentPoint; + startTime = Date.now(); + } + + const dx = currentPoint.x - startPoint.x; + const dy = currentPoint.y - startPoint.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + // 如果是点击(移动距离小于阈值且时间短) + if (isClick && distance < 5 && Date.now() - startTime < 200) { + return; // 不执行移动操作 + } + + // 标记为非点击操作 + isClick = false; + + // 执行移动操作 + if (lastPoint) { + const moveDx = currentPoint.x - lastPoint.x; + const moveDy = currentPoint.y - lastPoint.y; + + this.transformMatrix.tx += moveDx; + this.transformMatrix.ty += moveDy; + } + + lastPoint = currentPoint; + } + + // 在触摸结束时重置状态 + if (event.type === 'touchend' || event.type === 'touchcancel') { + isClick = true; + startPoint = null; + startTime = null; + lastPoint = null; + } + }; + }, + + async handleTouchEvent(event) { + console.log(event,'handleTouchEvent') + // 更新触点数量 + this.touchPoints = event.touches.length; + + // 仅在触摸开始时重置状态 + if (event.type === 'touchstart') { + this.gestureStatus = event.touches.length > 1 ? '双指开始' : '单指开始'; + } + + // 处理事件传递 + this.gestureHandler?.catchEvent(event); + + // 更新触摸结束状态 + if (event.type === 'touchend' || event.type === 'touchcancel') { + this.gestureStatus = '结束'; + this.updateCanvas(); + } + + // 限制更新频率 + const currentTime = Date.now(); + if (currentTime - this.lastGestureTime > 50) { + this.lastGestureTime = currentTime; + this.updateCanvas(); + } + }, + // 更新Canvas updateCanvas() { this.$nextTick(() => { @@ -595,29 +639,37 @@ export default { this.transformMatrix = new TransformMatrix(); // 自动居中显示座位区域 - this.$nextTick(() => { - if (this.seatPositions.length > 0) { - const minX = Math.min(...this.seatPositions.map(s => s.x)); - const maxX = Math.max(...this.seatPositions.map(s => s.x)); - const minY = Math.min(...this.seatPositions.map(s => s.y)); - const maxY = Math.max(...this.seatPositions.map(s => s.y)); - - const centerX = (minX + maxX) / 2; - const centerY = (minY + maxY) / 2; - - // 计算合适的缩放比例 - const widthRatio = this.canvasWidth / (maxX - minX + 100); - const heightRatio = this.canvasHeight / (maxY - minY + 100); - const scale = Math.min(widthRatio, heightRatio, 1); - - // 应用变换 - // this.transformMatrix.scale(scale, scale); - // this.transformMatrix.translate( - // this.canvasWidth/2 - centerX * scale, - // this.canvasHeight/2 - centerY * scale - // ); - } - }); + // 自动居中显示座位区域 + this.$nextTick(() => { + if (!this.gestureHandler) { + this.initGestureHandler(); + } + if (this.seatPositions.length > 0) { + // 计算座位区域边界 + const xs = this.seatPositions.map(s => s.x); + const ys = this.seatPositions.map(s => s.y); + const minX = Math.min(...xs); + const maxX = Math.max(...xs); + const minY = Math.min(...ys); + const maxY = Math.max(...ys); + + // 计算中心点 + const centerX = (minX + maxX) / 2; + const centerY = (minY + maxY) / 2; + + // 计算合适的缩放比例 + const widthRatio = this.canvasWidth / (maxX - minX + 100); + const heightRatio = this.canvasHeight / (maxY - minY + 100); + const scale = Math.min(widthRatio, heightRatio, 1); + + // 应用变换 + // this.transformMatrix.scale(scale, scale); + // this.transformMatrix.translate( + // this.canvasWidth/2 - centerX * scale, + // this.canvasHeight/2 - centerY * scale + // ); + } + }); } catch (e) { diff --git a/pages/index/gesture-handler.js b/pages/index/gesture-handler.js index 24ffdf9..28907a7 100644 --- a/pages/index/gesture-handler.js +++ b/pages/index/gesture-handler.js @@ -4,7 +4,8 @@ class GestureHandler { this.containerRect = container; this.panThreshold = 5; this.panStarted = false; - + // 保存父组件上下文 + this.context = context; // 判断是否是小程序环境 this.isMiniProgram = typeof wx !== 'undefined' || typeof uni !== 'undefined'; @@ -52,66 +53,63 @@ class GestureHandler { } } - // 创建小程序专用的简化手势处理器 - createSimpleGestureHandler() { - let isClick = true; - let startPoint = null; - let startTime = null; - let lastPoint = null; - - return (event) => { - const touches = event.touches || []; - - if (touches.length === 1) { - const getPoint = (t) => ({ - x: t.x || (t.clientX - this.containerRect.left), - y: t.y || (t.clientY - this.containerRect.top) - }); - - const currentPoint = getPoint(touches[0]); - - // 第一次触摸 - if (!startPoint) { - startPoint = currentPoint; - startTime = Date.now(); - } - - // 计算移动距离 - const dx = currentPoint.x - startPoint.x; - const dy = currentPoint.y - startPoint.y; - const distance = Math.sqrt(dx * dx + dy * dy); - - // 如果是点击(移动距离小于阈值且时间短) - if (isClick && distance < 5 && Date.now() - startTime < 200) { - return; // 不执行移动操作 - } - - // 标记为非点击操作 - isClick = false; - - // 执行移动操作 - if (lastPoint) { - const moveDx = currentPoint.x - lastPoint.x; - const moveDy = currentPoint.y - lastPoint.y; - - this.transformMatrix.tx += moveDx; - this.transformMatrix.ty += moveDy; - } - - lastPoint = currentPoint; - } else if (touches.length > 1) { - this._handlePinch(touches); - } - - // 在触摸结束时重置状态 - if (event.type === 'touchend' || event.type === 'touchcancel') { - isClick = true; - startPoint = null; - startTime = null; - lastPoint = null; - } - }; - } + createSimpleGestureHandler() { + let isClick = true; + let startPoint = null; + let startTime = null; + let lastPoint = null; + + return (event) => { + // 移除了视图判断 + const touches = event.touches || []; + + if (touches.length === 1) { + const getPoint = (t) => ({ + x: t.x || (t.clientX - this.containerRect.left), + y: t.y || (t.clientY - this.containerRect.top) + }); + + const currentPoint = getPoint(touches[0]); + + if (!startPoint) { + startPoint = currentPoint; + startTime = Date.now(); + } + + const dx = currentPoint.x - startPoint.x; + const dy = currentPoint.y - startPoint.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + // 区分点击和拖拽 + if (isClick && distance < 5 && Date.now() - startTime < 200) { + return; + } + + isClick = false; + + if (lastPoint) { + const moveDx = currentPoint.x - lastPoint.x; + const moveDy = currentPoint.y - lastPoint.y; + + this.transformMatrix.tx += moveDx; + this.transformMatrix.ty += moveDy; + } + + lastPoint = currentPoint; + } else if (touches.length > 1) { + this._handlePinch(touches); + } + + // 重置状态 + if (event.type === 'touchend' || event.type === 'touchcancel') { + isClick = true; + startPoint = null; + startTime = null; + lastPoint = null; + } + }; + } + setupGestures() { // 平移手势 diff --git a/pages/index/transform-canvas.vue b/pages/index/transform-canvas.vue index 77eb63b..1677be4 100644 --- a/pages/index/transform-canvas.vue +++ b/pages/index/transform-canvas.vue @@ -27,7 +27,8 @@ export default { }) }, areaData:{}, - seatData:{} + seatData:{}, + selectedCodes:{} }, data() { return { @@ -37,10 +38,17 @@ export default { canvasDisplayWidth: 800, // 默认显示尺寸 canvasDisplayHeight: 600, canvasActualWidth: 800, // 实际像素尺寸 - canvasActualHeight: 600 + canvasActualHeight: 600, + nowSelectedCodes:this.selectedCodes }; }, watch: { + selectedCodes:{ + handler(newVal) { + this.nowSelectedCodes = newVal + }, + immediate: true + }, imgUrl: { handler(newUrl) { if (newUrl) this.loadImage(newUrl); @@ -83,6 +91,13 @@ export default { this.initCanvas(); }, methods: { + + invertPoint(x, y) { + // 注意:直接使用矩阵的逆转换,不需要除以dpr + const inverted = this.matrix.invertPoint(x, y); + return inverted; + }, + // 添加点击检测方法 checkHitArea(x, y) { if (!this.areaData) return null; @@ -302,26 +317,62 @@ export default { }); }, drawSeats() { - // 获取当前缩放比例 - const scale = Math.sqrt(this.matrix.a * this.matrix.a + this.matrix.b * this.matrix.b); - - this.seatData.forEach(seat => { - // 使用原始坐标(变换矩阵会自动应用) - const x = seat.x; - const y = seat.y; - - this.ctx.beginPath(); - // 根据缩放调整座位大小 - const radius = 8 / scale; - this.ctx.arc(x, y, radius, 0, Math.PI * 2); - - this.ctx.fillStyle = seat.status === 1 ? '#4cd964' : '#dd524d'; - this.ctx.fill(); - - // 仅在缩放足够大时显示文字 - - }); + this.ctx.save(); + + // 应用变换矩阵 + const { a, b, c, d, tx, ty } = this.matrix; + this.ctx.setTransform(a, b, c, d, tx, ty); + + // 获取当前缩放比例 + const scale = Math.sqrt(a * a + b * b); + + this.seatData.forEach(seat => { + const x = seat.x; + const y = seat.y; + + // 根据缩放调整座位大小 + const radius = 8 / scale; + + console.log(this.nowSelectedCodes,'nowSelectedCodesnowSelectedCodesnowSelectedCodes') + // 修改1:为选中座位添加特殊样式 + if (this.nowSelectedCodes.has(seat.code) && seat.status === 1) { + // 1. 绘制金色边框 + this.ctx.beginPath(); + this.ctx.arc(x, y, radius + 1, 0, Math.PI * 2); + this.ctx.strokeStyle = '#FFD700'; // 金色 + this.ctx.lineWidth = 2 / scale; + this.ctx.stroke(); + + // 2. 绘制半透明金色背景 + this.ctx.beginPath(); + this.ctx.arc(x, y, radius, 0, Math.PI * 2); + this.ctx.fillStyle = 'rgba(255, 215, 0, 0.3)'; + this.ctx.fill(); + + // 3. 绘制白色对勾(缩小版) + this.ctx.strokeStyle = '#fff'; + this.ctx.lineWidth = 1 / scale; + this.ctx.lineCap = 'round'; + this.ctx.beginPath(); + this.ctx.moveTo(x - 2.5, y); + this.ctx.lineTo(x - 0.5, y + 1.5); + this.ctx.lineTo(x + 2.5, y - 2); + this.ctx.stroke(); + } else { + // 普通座位的绘制保持不变 + this.ctx.beginPath(); + this.ctx.arc(x, y, radius, 0, Math.PI * 2); + this.ctx.fillStyle = seat.status === 1 ? '#4cd964' : '#dd524d'; + this.ctx.fill(); + } + + // 仅在缩放足够大时显示文字 + + }); + + this.ctx.restore(); } + } } \ No newline at end of file diff --git a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-canvas-page.js.map b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-canvas-page.js.map index 02d0f29..86c6898 100644 --- a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-canvas-page.js.map +++ b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-canvas-page.js.map @@ -1 +1 @@ -{"version":3,"file":"gesture-canvas-page.js","sources":["pages/index/gesture-canvas-page.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/gesture-canvas-page.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"} \ No newline at end of file +{"version":3,"file":"gesture-canvas-page.js","sources":["pages/index/gesture-canvas-page.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/gesture-canvas-page.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-handler.js.map b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-handler.js.map index 5c1348f..edf98bb 100644 --- a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-handler.js.map +++ b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/gesture-handler.js.map @@ -1 +1 @@ -{"version":3,"file":"gesture-handler.js","sources":["pages/index/gesture-handler.js"],"sourcesContent":["class GestureHandler {\n constructor(context, transformMatrix, { container }) {\n this.transformMatrix = transformMatrix;\n this.containerRect = container;\n this.panThreshold = 5;\n this.panStarted = false;\n \n // 判断是否是小程序环境\n this.isMiniProgram = typeof wx !== 'undefined' || typeof uni !== 'undefined';\n \n // 小程序环境下直接使用降级方案\n if (this.isMiniProgram) {\n console.log('小程序环境,使用降级手势处理器');\n this.catchEvent = this.createSimpleGestureHandler();\n return;\n }\n \n // 非小程序环境尝试使用AnyTouch\n try {\n const atOptions = {\n getPoint: touch => ({\n x: touch.clientX - this.containerRect.left,\n y: touch.clientY - this.containerRect.top\n }),\n preventDefault: false\n };\n \n // 提供兼容小程序的虚拟元素\n atOptions.element = {\n style: {},\n addEventListener: () => {},\n removeEventListener: () => {},\n ownerDocument: {\n documentElement: {\n style: {}\n }\n }\n };\n \n // 动态导入AnyTouch避免小程序环境问题\n import('any-touch').then(AnyTouch => {\n this.at = new AnyTouch.default(atOptions);\n this.setupGestures();\n console.log('AnyTouch手势处理器已初始化');\n }).catch(e => {\n console.error('AnyTouch加载失败:', e);\n this.catchEvent = this.createSimpleGestureHandler();\n });\n } catch (e) {\n console.error('AnyTouch初始化失败:', e);\n this.catchEvent = this.createSimpleGestureHandler();\n }\n }\n \n // 创建小程序专用的简化手势处理器\n createSimpleGestureHandler() {\n let isClick = true;\n let startPoint = null;\n let startTime = null;\n let lastPoint = null;\n \n return (event) => {\n const touches = event.touches || [];\n \n if (touches.length === 1) {\n const getPoint = (t) => ({\n x: t.x || (t.clientX - this.containerRect.left),\n y: t.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoint = getPoint(touches[0]);\n \n // 第一次触摸\n if (!startPoint) {\n startPoint = currentPoint;\n startTime = Date.now();\n }\n \n // 计算移动距离\n const dx = currentPoint.x - startPoint.x;\n const dy = currentPoint.y - startPoint.y;\n const distance = Math.sqrt(dx * dx + dy * dy);\n \n // 如果是点击(移动距离小于阈值且时间短)\n if (isClick && distance < 5 && Date.now() - startTime < 200) {\n return; // 不执行移动操作\n }\n \n // 标记为非点击操作\n isClick = false;\n \n // 执行移动操作\n if (lastPoint) {\n const moveDx = currentPoint.x - lastPoint.x;\n const moveDy = currentPoint.y - lastPoint.y;\n \n this.transformMatrix.tx += moveDx;\n this.transformMatrix.ty += moveDy;\n }\n \n lastPoint = currentPoint;\n } else if (touches.length > 1) {\n this._handlePinch(touches);\n }\n \n // 在触摸结束时重置状态\n if (event.type === 'touchend' || event.type === 'touchcancel') {\n isClick = true;\n startPoint = null;\n startTime = null;\n lastPoint = null;\n }\n };\n }\n \n setupGestures() {\n // 平移手势\n this.at.on('pan', (event) => {\n if (event.type === 'panstart') {\n this.panStarted = false;\n }\n else if (event.type === 'panmove') {\n const distance = Math.sqrt(event.deltaX**2 + event.deltaY**2);\n \n if (!this.panStarted && distance < this.panThreshold) return;\n \n if (!this.panStarted) {\n this.panStarted = true;\n }\n \n const currentScale = Math.sqrt(\n this.transformMatrix.a * this.transformMatrix.a +\n this.transformMatrix.b * this.transformMatrix.b\n );\n \n const dx = event.deltaX / currentScale;\n const dy = event.deltaY / currentScale;\n \n this.transformMatrix.translate(dx, dy);\n } else if (event.type === 'panend') {\n this.panStarted = false;\n }\n });\n \n // 缩放手势\n this.at.on('pinch', (event) => {\n if (event.type === 'pinchstart') {\n this.lastScale = 1;\n }\n else if (event.type === 'pinchmove') {\n const scaleChange = event.scale / this.lastScale;\n this.lastScale = event.scale;\n \n const centerX = event.center.x;\n const centerY = event.center.y;\n \n this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);\n }\n });\n }\n \n // 公共接口\n catchEvent(event) {\n\t\t// 当触摸点数量变化时终止当前手势\n\t\tif (this.lastTouchCount !== event.touches.length) {\n\t\t\tthis.panStarted = false;\n\t\t\tthis.lastPoints = null;\n\t\t}\n\t\tthis.lastTouchCount = event.touches.length;\n\t\t\n try {\n if (this.at) {\n this.at.run(event);\n } else if (this.catchEvent) {\n this.catchEvent(event);\n }\n } catch (e) {\n console.error('手势处理错误:', e);\n }\n }\n \n // 基础平移手势处理\n _handlePan(touch) {\n const getPoint = (t) => ({\n x: t.x || (t.clientX - this.containerRect.left),\n y: t.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoint = getPoint(touch);\n \n if (this.lastPoint) {\n const dx = currentPoint.x - this.lastPoint.x;\n const dy = currentPoint.y - this.lastPoint.y;\n \n this.transformMatrix.tx += dx;\n this.transformMatrix.ty += dy;\n }\n \n this.lastPoint = currentPoint;\n }\n \n // 基础缩放手势处理\n _handlePinch(touches) {\n const point1 = touches[0];\n const point2 = touches[1];\n \n const getPoint = (touch) => ({\n x: touch.x || (touch.clientX - this.containerRect.left),\n y: touch.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoints = [getPoint(point1), getPoint(point2)];\n \n if (this.lastPoints) {\n const currentDistance = Math.sqrt(\n Math.pow(currentPoints[1].x - currentPoints[0].x, 2) + \n Math.pow(currentPoints[1].y - currentPoints[0].y, 2)\n );\n \n const prevDistance = Math.sqrt(\n Math.pow(this.lastPoints[1].x - this.lastPoints[0].x, 2) + \n Math.pow(this.lastPoints[1].y - this.lastPoints[0].y, 2)\n );\n \n if (prevDistance > 0 && currentDistance > 0) {\n const scaleChange = currentDistance / prevDistance;\n \n const centerX = (currentPoints[0].x + currentPoints[1].x) / 2;\n const centerY = (currentPoints[0].y + currentPoints[1].y) / 2;\n \n this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);\n }\n }\n \n this.lastPoints = currentPoints;\n }\n}\n\nexport default GestureHandler;"],"names":["wx","uni","t"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"gesture-handler.js","sources":["pages/index/gesture-handler.js"],"sourcesContent":["class GestureHandler {\n constructor(context, transformMatrix, { container }) {\n this.transformMatrix = transformMatrix;\n this.containerRect = container;\n this.panThreshold = 5;\n this.panStarted = false;\n\t\t// 保存父组件上下文\n\t\tthis.context = context;\n // 判断是否是小程序环境\n this.isMiniProgram = typeof wx !== 'undefined' || typeof uni !== 'undefined';\n \n // 小程序环境下直接使用降级方案\n if (this.isMiniProgram) {\n console.log('小程序环境,使用降级手势处理器');\n this.catchEvent = this.createSimpleGestureHandler();\n return;\n }\n \n // 非小程序环境尝试使用AnyTouch\n try {\n const atOptions = {\n getPoint: touch => ({\n x: touch.clientX - this.containerRect.left,\n y: touch.clientY - this.containerRect.top\n }),\n preventDefault: false\n };\n \n // 提供兼容小程序的虚拟元素\n atOptions.element = {\n style: {},\n addEventListener: () => {},\n removeEventListener: () => {},\n ownerDocument: {\n documentElement: {\n style: {}\n }\n }\n };\n \n // 动态导入AnyTouch避免小程序环境问题\n import('any-touch').then(AnyTouch => {\n this.at = new AnyTouch.default(atOptions);\n this.setupGestures();\n console.log('AnyTouch手势处理器已初始化');\n }).catch(e => {\n console.error('AnyTouch加载失败:', e);\n this.catchEvent = this.createSimpleGestureHandler();\n });\n } catch (e) {\n console.error('AnyTouch初始化失败:', e);\n this.catchEvent = this.createSimpleGestureHandler();\n }\n }\n \n createSimpleGestureHandler() {\n let isClick = true;\n let startPoint = null;\n let startTime = null;\n let lastPoint = null;\n \n return (event) => {\n // 移除了视图判断\n const touches = event.touches || [];\n \n if (touches.length === 1) {\n const getPoint = (t) => ({\n x: t.x || (t.clientX - this.containerRect.left),\n y: t.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoint = getPoint(touches[0]);\n \n if (!startPoint) {\n startPoint = currentPoint;\n startTime = Date.now();\n }\n \n const dx = currentPoint.x - startPoint.x;\n const dy = currentPoint.y - startPoint.y;\n const distance = Math.sqrt(dx * dx + dy * dy);\n \n // 区分点击和拖拽\n if (isClick && distance < 5 && Date.now() - startTime < 200) {\n return;\n }\n \n isClick = false;\n \n if (lastPoint) {\n const moveDx = currentPoint.x - lastPoint.x;\n const moveDy = currentPoint.y - lastPoint.y;\n \n this.transformMatrix.tx += moveDx;\n this.transformMatrix.ty += moveDy;\n }\n \n lastPoint = currentPoint;\n } else if (touches.length > 1) {\n this._handlePinch(touches);\n }\n \n // 重置状态\n if (event.type === 'touchend' || event.type === 'touchcancel') {\n isClick = true;\n startPoint = null;\n startTime = null;\n lastPoint = null;\n }\n };\n }\n \n \n setupGestures() {\n // 平移手势\n this.at.on('pan', (event) => {\n if (event.type === 'panstart') {\n this.panStarted = false;\n }\n else if (event.type === 'panmove') {\n const distance = Math.sqrt(event.deltaX**2 + event.deltaY**2);\n \n if (!this.panStarted && distance < this.panThreshold) return;\n \n if (!this.panStarted) {\n this.panStarted = true;\n }\n \n const currentScale = Math.sqrt(\n this.transformMatrix.a * this.transformMatrix.a +\n this.transformMatrix.b * this.transformMatrix.b\n );\n \n const dx = event.deltaX / currentScale;\n const dy = event.deltaY / currentScale;\n \n this.transformMatrix.translate(dx, dy);\n } else if (event.type === 'panend') {\n this.panStarted = false;\n }\n });\n \n // 缩放手势\n this.at.on('pinch', (event) => {\n if (event.type === 'pinchstart') {\n this.lastScale = 1;\n }\n else if (event.type === 'pinchmove') {\n const scaleChange = event.scale / this.lastScale;\n this.lastScale = event.scale;\n \n const centerX = event.center.x;\n const centerY = event.center.y;\n \n this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);\n }\n });\n }\n \n // 公共接口\n catchEvent(event) {\n\t\t// 当触摸点数量变化时终止当前手势\n\t\tif (this.lastTouchCount !== event.touches.length) {\n\t\t\tthis.panStarted = false;\n\t\t\tthis.lastPoints = null;\n\t\t}\n\t\tthis.lastTouchCount = event.touches.length;\n\t\t\n try {\n if (this.at) {\n this.at.run(event);\n } else if (this.catchEvent) {\n this.catchEvent(event);\n }\n } catch (e) {\n console.error('手势处理错误:', e);\n }\n }\n \n // 基础平移手势处理\n _handlePan(touch) {\n const getPoint = (t) => ({\n x: t.x || (t.clientX - this.containerRect.left),\n y: t.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoint = getPoint(touch);\n \n if (this.lastPoint) {\n const dx = currentPoint.x - this.lastPoint.x;\n const dy = currentPoint.y - this.lastPoint.y;\n \n this.transformMatrix.tx += dx;\n this.transformMatrix.ty += dy;\n }\n \n this.lastPoint = currentPoint;\n }\n \n // 基础缩放手势处理\n _handlePinch(touches) {\n const point1 = touches[0];\n const point2 = touches[1];\n \n const getPoint = (touch) => ({\n x: touch.x || (touch.clientX - this.containerRect.left),\n y: touch.y || (t.clientY - this.containerRect.top)\n });\n \n const currentPoints = [getPoint(point1), getPoint(point2)];\n \n if (this.lastPoints) {\n const currentDistance = Math.sqrt(\n Math.pow(currentPoints[1].x - currentPoints[0].x, 2) + \n Math.pow(currentPoints[1].y - currentPoints[0].y, 2)\n );\n \n const prevDistance = Math.sqrt(\n Math.pow(this.lastPoints[1].x - this.lastPoints[0].x, 2) + \n Math.pow(this.lastPoints[1].y - this.lastPoints[0].y, 2)\n );\n \n if (prevDistance > 0 && currentDistance > 0) {\n const scaleChange = currentDistance / prevDistance;\n \n const centerX = (currentPoints[0].x + currentPoints[1].x) / 2;\n const centerY = (currentPoints[0].y + currentPoints[1].y) / 2;\n \n this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);\n }\n }\n \n this.lastPoints = currentPoints;\n }\n}\n\nexport default GestureHandler;"],"names":["wx","uni","t"],"mappings":"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"} \ No newline at end of file diff --git a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/transform-canvas.js.map b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/transform-canvas.js.map index da7d179..9a4cc9c 100644 --- a/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/transform-canvas.js.map +++ b/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/transform-canvas.js.map @@ -1 +1 @@ -{"version":3,"file":"transform-canvas.js","sources":["/Users/sunmeng/Desktop/wx/canvas/pages/index/transform-canvas.vue?type=component"],"sourcesContent":["import Component from '/Users/sunmeng/Desktop/wx/canvas/pages/index/transform-canvas.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,gBAAgB,SAAS;"} \ No newline at end of file +{"version":3,"file":"transform-canvas.js","sources":["/Users/sunmeng/Desktop/wx/canvas/pages/index/transform-canvas.vue?type=component"],"sourcesContent":["import Component from '/Users/sunmeng/Desktop/wx/canvas/pages/index/transform-canvas.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,gBAAgB,SAAS;"} \ No newline at end of file diff --git a/unpackage/dist/dev/mp-weixin/common/vendor.js b/unpackage/dist/dev/mp-weixin/common/vendor.js index 1b30128..91afa99 100644 --- a/unpackage/dist/dev/mp-weixin/common/vendor.js +++ b/unpackage/dist/dev/mp-weixin/common/vendor.js @@ -6882,7 +6882,7 @@ function initOnError() { function initRuntimeSocketService() { const hosts = "127.0.0.1,172.10.0.127"; const port = "8090"; - const id = "mp-weixin_8j0jyd"; + const id = "mp-weixin_3NWJxu"; const lazy = typeof swan !== "undefined"; let restoreError = lazy ? () => { } : initOnError(); diff --git a/unpackage/dist/dev/mp-weixin/pages/index/gesture-canvas-page.js b/unpackage/dist/dev/mp-weixin/pages/index/gesture-canvas-page.js index 06b849c..fffb283 100644 --- a/unpackage/dist/dev/mp-weixin/pages/index/gesture-canvas-page.js +++ b/unpackage/dist/dev/mp-weixin/pages/index/gesture-canvas-page.js @@ -23,8 +23,10 @@ const _sfc_main = { currentView: "area", seatPositions: [], // 座位数据 - selectedArea: null + selectedArea: null, // 当前选中分区 + selectedCodes: /* @__PURE__ */ new Set() + // 存储选中的座位code }; }, async mounted() { @@ -42,8 +44,10 @@ const _sfc_main = { const dpr = this.$refs.canvasRef.dpr || 1; const x = (e.detail.x - this.containerRect.left) * dpr; const y = (e.detail.y - this.containerRect.top) * dpr; + common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:89", "handleCanvasClick", x, y); if (this.currentView === "area") { const hitArea = this.$refs.canvasRef.checkHitArea(x, y); + common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:92", "handleCanvasClick", hitArea); if (hitArea) { common_vendor.index.showModal({ title: "请确认", @@ -55,17 +59,34 @@ const _sfc_main = { this.currentView = "seat"; this.loadSeatData(hitArea.areacode); } - common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:102", res, "showModa-- success"); } }); } } else if (this.currentView === "seat") { const hitSeat = this.$refs.canvasRef.checkSeatHit(x, y); if (hitSeat) { - common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:109", "选中座位:", hitSeat); + common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:111", "选中座位:", hitSeat); + this.toggleSeatSelection(hitSeat); } } }, + toggleSeatSelection(seat) { + if (seat.status !== 1) + return; + if (this.selectedCodes.has(seat.code)) { + this.selectedCodes.delete(seat.code); + } else { + if (this.selectedCodes.size < 4) { + this.selectedCodes.add(seat.code); + } else { + common_vendor.index.showToast({ + title: "最多只能选择4个座位", + icon: "none" + }); + } + } + this.$refs.canvasRef.redraw(); + }, async getContainerPosition() { let retryCount = 0; const maxRetries = 3; @@ -87,7 +108,7 @@ const _sfc_main = { return; } } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:140", "获取容器位置失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:162", "获取容器位置失败:", e); } await new Promise((r) => setTimeout(r, 100)); retryCount++; @@ -98,59 +119,75 @@ const _sfc_main = { this.gestureHandler = new pages_index_gestureHandler.GestureHandler(this, this.transformMatrix, { container: this.containerRect }); + common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:176", "initGestureHandler", this.gestureHandler); } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:155", "手势处理器初始化失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:178", "手势处理器初始化失败:", e); this.gestureHandler = { - catchEvent: (event) => { - if (event.touches.length > 0) { - this.gestureStatus = "降级模式"; - this.touchPoints = event.touches.length; - if (event.type === "touchmove") { - const firstTouch = event.touches[0]; - const x = firstTouch.clientX - this.containerRect.left; - const y = firstTouch.clientY - this.containerRect.top; - this.transformMatrix.tx = x; - this.transformMatrix.ty = y; - this.updateCanvas(); - } - } + catchEvent: this.createGestureFallback(), + setScale: (scale) => { + this.transformMatrix.scale(scale, scale, this.canvasWidth / 2, this.canvasHeight / 2); + this.updateCanvas(); + }, + reset: () => { + this.transformMatrix.reset(); + this.updateCanvas(); } }; } }, - // 事件处理 - async handleTouchEvent(event) { - if (!this.gestureHandler || !this.containerRect) { - await this.getContainerPosition(); - this.initGestureHandler(); - if (event.type === "touchend" || event.type === "touchcancel") { - this.gestureStatus = "结束"; - this.updateCanvas(); - return; + createGestureFallback() { + let isClick = true; + let startPoint = null; + let startTime = null; + let lastPoint = null; + return (event) => { + const touches = event.touches || []; + if (touches.length === 1) { + const getPoint = (t) => ({ + x: t.clientX - this.containerRect.left, + y: t.clientY - this.containerRect.top + }); + const currentPoint = getPoint(touches[0]); + if (!startPoint) { + startPoint = currentPoint; + startTime = Date.now(); + } + const dx = currentPoint.x - startPoint.x; + const dy = currentPoint.y - startPoint.y; + const distance = Math.sqrt(dx * dx + dy * dy); + if (isClick && distance < 5 && Date.now() - startTime < 200) { + return; + } + isClick = false; + if (lastPoint) { + const moveDx = currentPoint.x - lastPoint.x; + const moveDy = currentPoint.y - lastPoint.y; + this.transformMatrix.tx += moveDx; + this.transformMatrix.ty += moveDy; + } + lastPoint = currentPoint; + } + if (event.type === "touchend" || event.type === "touchcancel") { + isClick = true; + startPoint = null; + startTime = null; + lastPoint = null; } - } - const currentTime = Date.now(); - this.touchPoints = event.touches.length; - const correctedTouches = Array.from(event.touches).map((touch) => { - return { - ...touch, - x: touch.clientX - this.containerRect.left, - y: touch.clientY - this.containerRect.top - }; - }); - const correctedEvent = { - ...event, - touches: correctedTouches, - changedTouches: correctedTouches }; - this.gestureHandler.catchEvent(correctedEvent); + }, + async handleTouchEvent(event) { + var _a; + common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:251", event, "handleTouchEvent"); + this.touchPoints = event.touches.length; if (event.type === "touchstart") { this.gestureStatus = event.touches.length > 1 ? "双指开始" : "单指开始"; - } else if (event.type === "touchmove") { - this.gestureStatus = event.touches.length > 1 ? "双指缩放/移动" : "单指移动"; - } else { - this.gestureStatus = "结束"; } + (_a = this.gestureHandler) == null ? void 0 : _a.catchEvent(event); + if (event.type === "touchend" || event.type === "touchcancel") { + this.gestureStatus = "结束"; + this.updateCanvas(); + } + const currentTime = Date.now(); if (currentTime - this.lastGestureTime > 50) { this.lastGestureTime = currentTime; this.updateCanvas(); @@ -491,7 +528,7 @@ const _sfc_main = { }; this.seatAreas = response.data; } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:574", "加载区域数据失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:618", "加载区域数据失败:", e); } }, async loadSeatData(areaCode) { @@ -512,11 +549,16 @@ const _sfc_main = { }); this.transformMatrix = new pages_index_transformMatrix.TransformMatrix(); this.$nextTick(() => { + if (!this.gestureHandler) { + this.initGestureHandler(); + } if (this.seatPositions.length > 0) { - const minX = Math.min(...this.seatPositions.map((s) => s.x)); - const maxX = Math.max(...this.seatPositions.map((s) => s.x)); - const minY = Math.min(...this.seatPositions.map((s) => s.y)); - const maxY = Math.max(...this.seatPositions.map((s) => s.y)); + const xs = this.seatPositions.map((s) => s.x); + const ys = this.seatPositions.map((s) => s.y); + const minX = Math.min(...xs); + const maxX = Math.max(...xs); + const minY = Math.min(...ys); + const maxY = Math.max(...ys); const centerX = (minX + maxX) / 2; const centerY = (minY + maxY) / 2; const widthRatio = this.canvasWidth / (maxX - minX + 100); @@ -525,7 +567,7 @@ const _sfc_main = { } }); } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:624", "加载座位数据失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:676", "加载座位数据失败:", e); common_vendor.index.showToast({ title: "加载座位失败", icon: "none" }); } } @@ -549,7 +591,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { matrix: $data.transformMatrix, imgUrl: "https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg", areaData: $data.currentView === "area" ? $data.seatAreas : [], - seatData: $data.currentView === "seat" ? $data.seatPositions : [] + seatData: $data.currentView === "seat" ? $data.seatPositions : [], + selectedCodes: $data.selectedCodes }), h: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)), i: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)), diff --git a/unpackage/dist/dev/mp-weixin/pages/index/gesture-handler.js b/unpackage/dist/dev/mp-weixin/pages/index/gesture-handler.js index 7e3aa97..83be726 100644 --- a/unpackage/dist/dev/mp-weixin/pages/index/gesture-handler.js +++ b/unpackage/dist/dev/mp-weixin/pages/index/gesture-handler.js @@ -6,9 +6,10 @@ class GestureHandler { this.containerRect = container; this.panThreshold = 5; this.panStarted = false; + this.context = context; this.isMiniProgram = typeof common_vendor.wx$1 !== "undefined" || typeof common_vendor.index !== "undefined"; if (this.isMiniProgram) { - common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:13", "小程序环境,使用降级手势处理器"); + common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:14", "小程序环境,使用降级手势处理器"); this.catchEvent = this.createSimpleGestureHandler(); return; } @@ -35,17 +36,16 @@ class GestureHandler { "../../common/vendor.js".then((n) => n.index_es).then((AnyTouch) => { this.at = new AnyTouch.default(atOptions); this.setupGestures(); - common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:44", "AnyTouch手势处理器已初始化"); + common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:45", "AnyTouch手势处理器已初始化"); }).catch((e) => { - common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:46", "AnyTouch加载失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:47", "AnyTouch加载失败:", e); this.catchEvent = this.createSimpleGestureHandler(); }); } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:50", "AnyTouch初始化失败:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:51", "AnyTouch初始化失败:", e); this.catchEvent = this.createSimpleGestureHandler(); } } - // 创建小程序专用的简化手势处理器 createSimpleGestureHandler() { let isClick = true; let startPoint = null; @@ -135,7 +135,7 @@ class GestureHandler { this.catchEvent(event); } } catch (e) { - common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:178", "手势处理错误:", e); + common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:176", "手势处理错误:", e); } } // 基础平移手势处理 diff --git a/unpackage/dist/dev/mp-weixin/pages/index/transform-canvas.js b/unpackage/dist/dev/mp-weixin/pages/index/transform-canvas.js index 138da9c..68ab765 100644 --- a/unpackage/dist/dev/mp-weixin/pages/index/transform-canvas.js +++ b/unpackage/dist/dev/mp-weixin/pages/index/transform-canvas.js @@ -21,7 +21,8 @@ const _sfc_main = { }) }, areaData: {}, - seatData: {} + seatData: {}, + selectedCodes: {} }, data() { return { @@ -33,10 +34,17 @@ const _sfc_main = { canvasDisplayHeight: 600, canvasActualWidth: 800, // 实际像素尺寸 - canvasActualHeight: 600 + canvasActualHeight: 600, + nowSelectedCodes: this.selectedCodes }; }, watch: { + selectedCodes: { + handler(newVal) { + this.nowSelectedCodes = newVal; + }, + immediate: true + }, imgUrl: { handler(newUrl) { if (newUrl) @@ -81,12 +89,16 @@ const _sfc_main = { this.initCanvas(); }, methods: { + invertPoint(x, y) { + const inverted = this.matrix.invertPoint(x, y); + return inverted; + }, // 添加点击检测方法 checkHitArea(x, y) { if (!this.areaData) return null; const inverted = this.matrix.invertPoint(x, y, this.dpr); - common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:92", "checkHitArea", inverted); + common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:107", "checkHitArea", inverted); for (const area of this.areaData) { if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) { return area; @@ -173,7 +185,7 @@ const _sfc_main = { }); this.redraw(); } catch (e) { - common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:223", "图片加载失败:", e); + common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:238", "图片加载失败:", e); this.image = null; } }, @@ -242,16 +254,40 @@ const _sfc_main = { }); }, drawSeats() { - const scale = Math.sqrt(this.matrix.a * this.matrix.a + this.matrix.b * this.matrix.b); + this.ctx.save(); + const { a, b, c, d, tx, ty } = this.matrix; + this.ctx.setTransform(a, b, c, d, tx, ty); + const scale = Math.sqrt(a * a + b * b); this.seatData.forEach((seat) => { const x = seat.x; const y = seat.y; - this.ctx.beginPath(); const radius = 8 / scale; - this.ctx.arc(x, y, radius, 0, Math.PI * 2); - this.ctx.fillStyle = seat.status === 1 ? "#4cd964" : "#dd524d"; - this.ctx.fill(); + if (this.nowSelectedCodes.has(seat.code) && seat.status === 1) { + this.ctx.beginPath(); + this.ctx.arc(x, y, radius + 1, 0, Math.PI * 2); + this.ctx.strokeStyle = "#FFD700"; + this.ctx.lineWidth = 2 / scale; + this.ctx.stroke(); + this.ctx.beginPath(); + this.ctx.arc(x, y, radius, 0, Math.PI * 2); + this.ctx.fillStyle = "rgba(255, 215, 0, 0.3)"; + this.ctx.fill(); + this.ctx.strokeStyle = "#fff"; + this.ctx.lineWidth = 1 / scale; + this.ctx.lineCap = "round"; + this.ctx.beginPath(); + this.ctx.moveTo(x - 2.5, y); + this.ctx.lineTo(x - 0.5, y + 1.5); + this.ctx.lineTo(x + 2.5, y - 2); + this.ctx.stroke(); + } else { + this.ctx.beginPath(); + this.ctx.arc(x, y, radius, 0, Math.PI * 2); + this.ctx.fillStyle = seat.status === 1 ? "#4cd964" : "#dd524d"; + this.ctx.fill(); + } }); + this.ctx.restore(); } } };