This commit is contained in:
sunmeng 2025-08-13 18:14:56 +08:00
parent a0129fa7ce
commit ed07181a5e
10 changed files with 446 additions and 266 deletions

View File

@ -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"
/>
</view>
<!-- isShowSeat -->
@ -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) {

View File

@ -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() {
// 平移手势

View File

@ -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();
}
}
}
</script>

View File

@ -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;"}
{"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;"}

File diff suppressed because one or more lines are too long

View File

@ -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;"}
{"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;"}

View File

@ -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();

View File

@ -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)),

View File

@ -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);
}
}
// 基础平移手势处理

View File

@ -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();
}
}
};