图片绘制 多边形绘制
This commit is contained in:
parent
4aa49ccbde
commit
40437fd728
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container">
|
<view class="container" @click="handleCanvasClick">
|
||||||
<view class="gesture-container"
|
<view class="gesture-container"
|
||||||
@touchstart="handleTouchEvent"
|
@touchstart="handleTouchEvent"
|
||||||
@touchmove="handleTouchEvent"
|
@touchmove="handleTouchEvent"
|
||||||
@ -18,15 +18,16 @@
|
|||||||
:width="canvasWidth"
|
:width="canvasWidth"
|
||||||
:height="canvasHeight"
|
:height="canvasHeight"
|
||||||
:matrix="transformMatrix"
|
:matrix="transformMatrix"
|
||||||
:imgUrl="'https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg'"
|
:imgUrl="'https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg'"
|
||||||
|
:areaData="seatAreas"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="controls">
|
<!-- <view class="controls">
|
||||||
<button @click="resetCanvas">重置</button>
|
<button @click="resetCanvas">重置</button>
|
||||||
<button @click="zoomIn">放大</button>
|
<button @click="zoomIn">放大</button>
|
||||||
<button @click="zoomOut">缩小</button>
|
<button @click="zoomOut">缩小</button>
|
||||||
</view>
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -50,122 +51,114 @@ export default {
|
|||||||
gestureStatus: '等待手势...',
|
gestureStatus: '等待手势...',
|
||||||
scaleValue: 1,
|
scaleValue: 1,
|
||||||
touchPoints: 0,
|
touchPoints: 0,
|
||||||
lastGestureTime: 0
|
lastGestureTime: 0,
|
||||||
|
seatAreas: [] // 座位区域数据
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.getContainerPosition();
|
await this.getContainerPosition();
|
||||||
|
this.initGestureHandler();
|
||||||
// 2. 初始化手势处理器(传入容器位置信息)
|
|
||||||
this.initGestureHandler();
|
// 加载座位区域数据
|
||||||
|
await this.loadSeatAreas();
|
||||||
// 3. 初始绘制
|
|
||||||
this.$nextTick(() => {
|
// 初始绘制
|
||||||
this.updateCanvas();
|
this.$nextTick(() => {
|
||||||
});
|
this.updateCanvas();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 独立的手势初始化方法
|
handleCanvasClick(e) {
|
||||||
initGestureHandler() {
|
if (!this.containerRect) return;
|
||||||
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) {
|
|
||||||
const firstTouch = event.touches[0];
|
|
||||||
const x = firstTouch.clientX - this.containerRect.left;
|
|
||||||
const y = firstTouch.clientY - this.containerRect.top;
|
|
||||||
|
|
||||||
// 仅更新调试信息显示
|
|
||||||
this.gestureStatus = "降级模式: 单指拖动";
|
|
||||||
this.touchPoints = event.touches.length;
|
|
||||||
|
|
||||||
// 简单变换
|
|
||||||
if (event.type === 'touchmove') {
|
|
||||||
this.transformMatrix.tx = x;
|
|
||||||
this.transformMatrix.ty = y;
|
|
||||||
this.updateCanvas();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getContainerPosition() {
|
|
||||||
// 添加重试机制
|
|
||||||
let retryCount = 0;
|
|
||||||
const maxRetries = 3;
|
|
||||||
|
|
||||||
while (retryCount < maxRetries) {
|
// 计算相对坐标
|
||||||
try {
|
const x = e.detail.x - this.containerRect.left;
|
||||||
const rect = await new Promise(resolve => {
|
const y = e.detail.y - this.containerRect.top;
|
||||||
const query = uni.createSelectorQuery().in(this);
|
|
||||||
query.select('.gesture-container').boundingClientRect(res => {
|
// 检测点击区域
|
||||||
resolve(res);
|
const hitArea = this.$refs.canvasRef.checkHitArea(x, y);
|
||||||
}).exec();
|
console.log('hitArea',hitArea)
|
||||||
});
|
if (hitArea) {
|
||||||
|
console.log('点击区域:', hitArea);
|
||||||
if (rect) {
|
|
||||||
this.containerRect = {
|
|
||||||
left: rect.left,
|
|
||||||
top: rect.top,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height
|
|
||||||
};
|
|
||||||
console.log('成功获取容器位置:', this.containerRect);
|
|
||||||
return; // 成功获取则退出
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('获取容器位置失败:', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待后重试
|
|
||||||
await new Promise(r => setTimeout(r, 100));
|
|
||||||
retryCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(`容器位置获取失败,已重试${maxRetries}次`);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getContainerPosition() {
|
||||||
|
// 添加重试机制
|
||||||
|
let retryCount = 0;
|
||||||
|
const maxRetries = 3;
|
||||||
|
|
||||||
|
while (retryCount < maxRetries) {
|
||||||
|
try {
|
||||||
|
const rect = await new Promise(resolve => {
|
||||||
|
const query = uni.createSelectorQuery().in(this);
|
||||||
|
query.select('.gesture-container').boundingClientRect(res => {
|
||||||
|
resolve(res);
|
||||||
|
}).exec();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rect) {
|
||||||
|
this.containerRect = {
|
||||||
|
left: rect.left,
|
||||||
|
top: rect.top,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取容器位置失败:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待后重试
|
||||||
|
await new Promise(r => setTimeout(r, 100));
|
||||||
|
retryCount++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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) {
|
async handleTouchEvent(event) {
|
||||||
|
if (!this.gestureHandler || !this.containerRect) {
|
||||||
if (!this.gestureHandler || !this.containerRect) {
|
await this.getContainerPosition();
|
||||||
console.warn('手势处理器未就绪,尝试重新初始化...');
|
this.initGestureHandler();
|
||||||
await this.getContainerPosition();
|
if (event.type === 'touchend' || event.type === 'touchcancel') {
|
||||||
this.initGestureHandler();
|
this.gestureStatus = '结束';
|
||||||
if (event.type === 'touchend' || event.type === 'touchcancel') {
|
this.updateCanvas();
|
||||||
this.lastPoint = null;
|
return;
|
||||||
this.lastPoints = null;
|
}
|
||||||
this.gestureStatus = '结束';
|
}
|
||||||
|
|
||||||
// 更新一次画面
|
|
||||||
this.updateCanvas();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 直接传递原始事件,手势处理器会处理坐标转换
|
|
||||||
this.gestureHandler.catchEvent(event);
|
|
||||||
|
|
||||||
// 如果是简单处理器,使用下面优化的基础处理方法
|
|
||||||
if (!this.at) {
|
|
||||||
// 使用优化后的基础处理方法
|
|
||||||
if (correctedEvent.touches.length === 1) {
|
|
||||||
this.handlePan(correctedEvent.touches[0]);
|
|
||||||
} else if (correctedEvent.touches.length > 1) {
|
|
||||||
this.handlePinch(correctedEvent.touches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 记录时间戳
|
// 记录时间戳
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
@ -173,17 +166,12 @@ export default {
|
|||||||
// 更新触点数量
|
// 更新触点数量
|
||||||
this.touchPoints = event.touches.length;
|
this.touchPoints = event.touches.length;
|
||||||
|
|
||||||
// 修正坐标(核心修复点)
|
// 修正坐标
|
||||||
const correctedTouches = Array.from(event.touches).map(touch => {
|
const correctedTouches = Array.from(event.touches).map(touch => {
|
||||||
const x = touch.clientX - this.containerRect.left;
|
|
||||||
const y = touch.clientY - this.containerRect.top;
|
|
||||||
|
|
||||||
console.log(`原始坐标: (${touch.clientX}, ${touch.clientY}) 修正后: (${x}, ${y})`);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...touch,
|
...touch,
|
||||||
x: x,
|
x: touch.clientX - this.containerRect.left,
|
||||||
y: y
|
y: touch.clientY - this.containerRect.top
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -208,26 +196,20 @@ export default {
|
|||||||
this.gestureStatus = '结束';
|
this.gestureStatus = '结束';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 限制更新频率:至少每50ms更新一次
|
// 限制更新频率
|
||||||
if (currentTime - this.lastGestureTime > 50) {
|
if (currentTime - this.lastGestureTime > 50) {
|
||||||
this.lastGestureTime = currentTime;
|
this.lastGestureTime = currentTime;
|
||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 更新Canvas(性能优化版)
|
// 更新Canvas
|
||||||
updateCanvas() {
|
updateCanvas() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const canvas = this.$refs.canvasRef;
|
this.scaleValue = Math.sqrt(
|
||||||
if (canvas) {
|
this.transformMatrix.a * this.transformMatrix.a +
|
||||||
// canvas.draw();
|
this.transformMatrix.b * this.transformMatrix.b
|
||||||
|
);
|
||||||
// 计算当前缩放值
|
|
||||||
this.scaleValue = Math.sqrt(
|
|
||||||
this.transformMatrix.a * this.transformMatrix.a +
|
|
||||||
this.transformMatrix.b * this.transformMatrix.b
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -251,20 +233,34 @@ export default {
|
|||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 加载座位区域数据
|
||||||
|
async loadSeatAreas() {
|
||||||
|
try {
|
||||||
|
// 模拟API请求
|
||||||
|
const response = {
|
||||||
|
"code":200,
|
||||||
|
"message":"",
|
||||||
|
"data":[{"areacode":"03tkrrjukrgu","areaname":"主席台","description":"主席台","remain":100,"polygon":[262,154,262,165,262,177,262,188,314,188,365,188,417,188,417,177,417,165,417,154,365,154,314,154,262,154]},{"areacode":"ea0jg3jukrgw","areaname":"A区","description":"A区","remain":1000,"polygon":[105,94,105,125,105,158,105,189,183,189,251,189,250,147,336,147,337,125,337,94,259,94,183,94,105,94]},{"areacode":"832fe6ej0kqc","areaname":"C区","description":"C区","remain":1000,"polygon":[106,418,106,452,106,487,106,521,183,521,261,521,338,521,338,487,338,452,338,418,261,418,183,418,106,418]},{"areacode":"p5naxqej0kqd","areaname":"B区","description":"B区","remain":1000,"polygon":[345,93,345,125,344,147,425,148,425,188,499,190,576,190,576,158,576,125,576,93,499,93,422,93,345,93]},{"areacode":"uknpk3sa819j","areaname":"D区","description":"D区","remain":1000,"polygon":[347,419,347,453,347,487,347,521,423,521,499,521,575,521,575,487,575,453,575,419,499,419,423,419,347,419]}]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.seatAreas = response.data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载区域数据失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container {
|
.container {
|
||||||
padding: 20px;
|
/* padding: 20px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.gesture-container {
|
.gesture-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 300px;
|
width: 100%;
|
||||||
height: 300px;
|
/* height: 70vh; */
|
||||||
border: 1px solid #ccc;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,169 +1,179 @@
|
|||||||
import AnyTouch from 'any-touch'
|
|
||||||
|
|
||||||
class GestureHandler {
|
class GestureHandler {
|
||||||
constructor(context, transformMatrix, { container }) {
|
constructor(context, transformMatrix, { container }) {
|
||||||
this.transformMatrix = transformMatrix;
|
this.transformMatrix = transformMatrix;
|
||||||
this.containerRect = container;
|
this.containerRect = container;
|
||||||
this.panThreshold = 5; // 移动5像素以上才认为是拖动
|
this.panThreshold = 5;
|
||||||
this.panStarted = false;
|
this.panStarted = false;
|
||||||
|
|
||||||
// 小程序环境兼容处理
|
// 判断是否是小程序环境
|
||||||
const atOptions = {
|
this.isMiniProgram = typeof wx !== 'undefined' || typeof uni !== 'undefined';
|
||||||
getPoint: touch => ({
|
|
||||||
x: touch.clientX - this.containerRect.left,
|
|
||||||
y: touch.clientY - this.containerRect.top
|
|
||||||
}),
|
|
||||||
preventDefault: false
|
|
||||||
};
|
|
||||||
|
|
||||||
// 小程序特化处理 - 跳过DOM相关操作
|
// 小程序环境下直接使用降级方案
|
||||||
if (typeof window === 'undefined' || typeof HTMLElement === 'undefined') {
|
if (this.isMiniProgram) {
|
||||||
// 小程序环境下不需要设置DOM属性
|
console.log('小程序环境,使用降级手势处理器');
|
||||||
atOptions._element = {
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非小程序环境尝试使用AnyTouch
|
||||||
|
try {
|
||||||
|
const atOptions = {
|
||||||
|
getPoint: touch => ({
|
||||||
|
x: touch.clientX - this.containerRect.left,
|
||||||
|
y: touch.clientY - this.containerRect.top
|
||||||
|
}),
|
||||||
|
preventDefault: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提供兼容小程序的虚拟元素
|
||||||
|
atOptions.element = {
|
||||||
style: {},
|
style: {},
|
||||||
addEventListener: () => {},
|
addEventListener: () => {},
|
||||||
removeEventListener: () => {}
|
removeEventListener: () => {},
|
||||||
|
ownerDocument: {
|
||||||
|
documentElement: {
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
// 动态导入AnyTouch避免小程序环境问题
|
||||||
try {
|
import('any-touch').then(AnyTouch => {
|
||||||
this.at = new AnyTouch(atOptions);
|
this.at = new AnyTouch.default(atOptions);
|
||||||
|
this.setupGestures();
|
||||||
|
console.log('AnyTouch手势处理器已初始化');
|
||||||
|
}).catch(e => {
|
||||||
|
console.error('AnyTouch加载失败:', e);
|
||||||
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('AnyTouch初始化失败:', e);
|
console.error('AnyTouch初始化失败:', e);
|
||||||
// 降级方案:在小程序环境实现基本手势
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
this.handleGesture = this.createSimpleGestureHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.at) {
|
|
||||||
this.setupGestures();
|
|
||||||
console.log('AnyTouch手势处理器已初始化');
|
|
||||||
} else {
|
|
||||||
console.warn('使用简化手势处理器');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建小程序专用的简化手势处理器
|
// 创建小程序专用的简化手势处理器
|
||||||
createSimpleGestureHandler() {
|
createSimpleGestureHandler() {
|
||||||
return {
|
let isClick = true;
|
||||||
run: (event) => {
|
let startPoint = null;
|
||||||
// 小程序环境下的基本手势实现
|
let startTime = null;
|
||||||
const touches = event.touches || [];
|
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)
|
||||||
|
});
|
||||||
|
|
||||||
if (touches.length === 1) {
|
const currentPoint = getPoint(touches[0]);
|
||||||
// 单指移动
|
|
||||||
this._handlePan(touches[0]);
|
// 第一次触摸
|
||||||
} else if (touches.length > 1) {
|
if (!startPoint) {
|
||||||
// 双指缩放
|
startPoint = currentPoint;
|
||||||
this._handlePinch(touches);
|
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() {
|
setupGestures() {
|
||||||
// 平移手势 - 修复版本
|
// 平移手势
|
||||||
this.at.on('pan', (event) => {
|
this.at.on('pan', (event) => {
|
||||||
if (event.type === 'panstart') {
|
if (event.type === 'panstart') {
|
||||||
console.log('panstart', event);
|
this.panStarted = false;
|
||||||
// 重置移动开始状态
|
|
||||||
this.panStarted = false;
|
|
||||||
}
|
}
|
||||||
else if (event.type === 'panmove') {
|
else if (event.type === 'panmove') {
|
||||||
// 检查是否超过阈值
|
const distance = Math.sqrt(event.deltaX**2 + event.deltaY**2);
|
||||||
const distance = Math.sqrt(event.deltaX**2 + event.deltaY**2);
|
|
||||||
|
if (!this.panStarted && distance < this.panThreshold) return;
|
||||||
if (!this.panStarted && distance < this.panThreshold) {
|
|
||||||
return; // 小于阈值不处理
|
if (!this.panStarted) {
|
||||||
}
|
this.panStarted = true;
|
||||||
|
}
|
||||||
if (!this.panStarted) {
|
|
||||||
console.log('拖动手势开始');
|
|
||||||
this.panStarted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 基于当前缩放比例修正移动量
|
|
||||||
const currentScale = Math.sqrt(
|
const currentScale = Math.sqrt(
|
||||||
this.transformMatrix.a * this.transformMatrix.a +
|
this.transformMatrix.a * this.transformMatrix.a +
|
||||||
this.transformMatrix.b * this.transformMatrix.b
|
this.transformMatrix.b * this.transformMatrix.b
|
||||||
);
|
);
|
||||||
|
|
||||||
// 逆缩放移动量
|
|
||||||
const dx = event.deltaX / currentScale;
|
const dx = event.deltaX / currentScale;
|
||||||
const dy = event.deltaY / currentScale;
|
const dy = event.deltaY / currentScale;
|
||||||
|
|
||||||
|
|
||||||
console.log(`平移: deltaX=${event.deltaX}, deltaY=${event.deltaY} | 修正后: dx=${dx}, dy=${dy}`);
|
|
||||||
|
|
||||||
this.transformMatrix.translate(dx, dy);
|
this.transformMatrix.translate(dx, dy);
|
||||||
} else if (event.type === 'panend') {
|
} else if (event.type === 'panend') {
|
||||||
this.panStarted = false;
|
this.panStarted = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 缩放手势 - 修复版本
|
// 缩放手势
|
||||||
this.at.on('pinch', (event) => {
|
this.at.on('pinch', (event) => {
|
||||||
if (event.type === 'pinchstart') {
|
if (event.type === 'pinchstart') {
|
||||||
this.lastScale = 1;
|
this.lastScale = 1;
|
||||||
}
|
}
|
||||||
else if (event.type === 'pinchmove') {
|
else if (event.type === 'pinchmove') {
|
||||||
// 计算缩放变化量
|
|
||||||
const scaleChange = event.scale / this.lastScale;
|
const scaleChange = event.scale / this.lastScale;
|
||||||
this.lastScale = event.scale;
|
this.lastScale = event.scale;
|
||||||
|
|
||||||
// 使用两指中心点
|
|
||||||
const centerX = event.center.x;
|
const centerX = event.center.x;
|
||||||
const centerY = event.center.y;
|
const centerY = event.center.y;
|
||||||
|
|
||||||
console.log(`缩放: scale=${event.scale} | 变化=${scaleChange} | 中心点: (${centerX}, ${centerY})`);
|
|
||||||
|
|
||||||
// 应用缩放
|
|
||||||
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 点击手势
|
|
||||||
this.at.on('tap', (event) => {
|
|
||||||
console.log('点击事件', event);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 长按手势
|
|
||||||
this.at.on('press', (event) => {
|
|
||||||
console.log('长按事件', event);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 公共接口
|
||||||
// 公共接口保持不变
|
catchEvent(event) {
|
||||||
catchEvent(event) {
|
try {
|
||||||
try {
|
if (this.at) {
|
||||||
if (this.at) {
|
this.at.run(event);
|
||||||
this.at.run(event);
|
} else if (this.catchEvent) {
|
||||||
} else {
|
this.catchEvent(event);
|
||||||
// 内部处理降级方案
|
|
||||||
const touches = event.touches || [];
|
|
||||||
const eventType = event.type;
|
|
||||||
|
|
||||||
// 在事件开始时重置状态
|
|
||||||
if (eventType === 'touchstart') {
|
|
||||||
this.lastPoint = null;
|
|
||||||
this.lastPoints = null;
|
|
||||||
this.lastDistance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理不同数量的手指
|
|
||||||
if (touches.length === 1) {
|
|
||||||
this._handlePan(touches[0]);
|
|
||||||
} else if (touches.length > 1) {
|
|
||||||
this._handlePinch(touches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('手势处理错误:', e);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('手势处理错误:', e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 基础平移手势处理
|
// 基础平移手势处理
|
||||||
_handlePan(touch) {
|
_handlePan(touch) {
|
||||||
// 获取容器坐标系坐标(统一计算方法)
|
|
||||||
const getPoint = (t) => ({
|
const getPoint = (t) => ({
|
||||||
x: t.x || (t.clientX - this.containerRect.left),
|
x: t.x || (t.clientX - this.containerRect.left),
|
||||||
y: t.y || (t.clientY - this.containerRect.top)
|
y: t.y || (t.clientY - this.containerRect.top)
|
||||||
@ -172,59 +182,50 @@ class GestureHandler {
|
|||||||
const currentPoint = getPoint(touch);
|
const currentPoint = getPoint(touch);
|
||||||
|
|
||||||
if (this.lastPoint) {
|
if (this.lastPoint) {
|
||||||
// 计算增量(使用容器坐标系)
|
|
||||||
const dx = currentPoint.x - this.lastPoint.x;
|
const dx = currentPoint.x - this.lastPoint.x;
|
||||||
const dy = currentPoint.y - this.lastPoint.y;
|
const dy = currentPoint.y - this.lastPoint.y;
|
||||||
|
|
||||||
// 应用平移变换
|
|
||||||
this.transformMatrix.tx += dx;
|
this.transformMatrix.tx += dx;
|
||||||
this.transformMatrix.ty += dy;
|
this.transformMatrix.ty += dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 存储当前点
|
|
||||||
this.lastPoint = currentPoint;
|
this.lastPoint = currentPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基础缩放手势处理
|
// 基础缩放手势处理
|
||||||
_handlePinch(touches) {
|
_handlePinch(touches) {
|
||||||
const point1 = touches[0];
|
const point1 = touches[0];
|
||||||
const point2 = touches[1];
|
const point2 = touches[1];
|
||||||
|
|
||||||
// 获取容器坐标系坐标
|
const getPoint = (touch) => ({
|
||||||
const getPoint = (touch) => ({
|
x: touch.x || (touch.clientX - this.containerRect.left),
|
||||||
x: touch.x || (touch.clientX - this.containerRect.left),
|
y: touch.y || (t.clientY - this.containerRect.top)
|
||||||
y: touch.y || (touch.clientY - this.containerRect.top)
|
});
|
||||||
});
|
|
||||||
|
const currentPoints = [getPoint(point1), getPoint(point2)];
|
||||||
const currentPoints = [getPoint(point1), getPoint(point2)];
|
|
||||||
|
if (this.lastPoints) {
|
||||||
if (this.lastPoints) {
|
const currentDistance = Math.sqrt(
|
||||||
// 计算当前距离 (容器坐标系)
|
Math.pow(currentPoints[1].x - currentPoints[0].x, 2) +
|
||||||
const currentDistance = Math.sqrt(
|
Math.pow(currentPoints[1].y - currentPoints[0].y, 2)
|
||||||
Math.pow(currentPoints[1].x - currentPoints[0].x, 2) +
|
);
|
||||||
Math.pow(currentPoints[1].y - currentPoints[0].y, 2)
|
|
||||||
);
|
const prevDistance = Math.sqrt(
|
||||||
|
Math.pow(this.lastPoints[1].x - this.lastPoints[0].x, 2) +
|
||||||
// 上次距离 (容器坐标系)
|
Math.pow(this.lastPoints[1].y - this.lastPoints[0].y, 2)
|
||||||
const prevDistance = Math.sqrt(
|
);
|
||||||
Math.pow(this.lastPoints[1].x - this.lastPoints[0].x, 2) +
|
|
||||||
Math.pow(this.lastPoints[1].y - this.lastPoints[0].y, 2)
|
if (prevDistance > 0 && currentDistance > 0) {
|
||||||
);
|
const scaleChange = currentDistance / prevDistance;
|
||||||
|
|
||||||
// 缩放比例
|
const centerX = (currentPoints[0].x + currentPoints[1].x) / 2;
|
||||||
if (prevDistance > 0 && currentDistance > 0) {
|
const centerY = (currentPoints[0].y + currentPoints[1].y) / 2;
|
||||||
const scaleChange = currentDistance / prevDistance;
|
|
||||||
|
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
||||||
// 计算中心点 (容器坐标系)
|
}
|
||||||
const centerX = (currentPoints[0].x + currentPoints[1].x) / 2;
|
}
|
||||||
const centerY = (currentPoints[0].y + currentPoints[1].y) / 2;
|
|
||||||
|
this.lastPoints = currentPoints;
|
||||||
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 存储当前点
|
|
||||||
this.lastPoints = currentPoints;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ export default {
|
|||||||
default: () => ({
|
default: () => ({
|
||||||
a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
|
a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
areaData:{}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -69,6 +70,121 @@ export default {
|
|||||||
this.initCanvas();
|
this.initCanvas();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 添加点击检测方法
|
||||||
|
checkHitArea(x, y) {
|
||||||
|
if (!this.areaData) return null;
|
||||||
|
|
||||||
|
// 转换坐标到原始画布空间
|
||||||
|
const inverted = this.matrix.invertPoint(x, y);
|
||||||
|
console.log('checkHitArea',inverted)
|
||||||
|
// 遍历所有区域检测
|
||||||
|
for (const area of this.areaData) {
|
||||||
|
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
|
||||||
|
return area.areacode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
// 射线法判断点是否在多边形内
|
||||||
|
// pointInPolygon(x, y, polygon) {
|
||||||
|
// // console.log('pointInPolygon',x, y, polygon)
|
||||||
|
// // 确保多边形有足够的点构成
|
||||||
|
// if (!polygon || polygon.length < 6) return false;
|
||||||
|
|
||||||
|
// let inside = false;
|
||||||
|
// const length = polygon.length;
|
||||||
|
|
||||||
|
// // 不需要遍历最后一个点,因为它是闭合点(与第一个点相同)
|
||||||
|
// for (let i = 0, j = length - 2; i < length; j = i, i += 2) {
|
||||||
|
// const xi = polygon[i], yi = polygon[i + 1];
|
||||||
|
// const xj = polygon[j], yj = polygon[j + 1];
|
||||||
|
|
||||||
|
// // 检查点是否在边的y值范围内
|
||||||
|
// const intersect = ((yi > y) !== (yj > y));
|
||||||
|
|
||||||
|
// // 检查点是否在边的左侧
|
||||||
|
// if (intersect) {
|
||||||
|
// const slope = (xj - xi) / (yj - yi); // 边的斜率
|
||||||
|
// const intersectX = xi + (y - yi) * slope;
|
||||||
|
|
||||||
|
// if (x < intersectX) {
|
||||||
|
// inside = !inside;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return inside;
|
||||||
|
// },
|
||||||
|
|
||||||
|
// 在 transform-canvas.vue 中替换 pointInPolygon 方法
|
||||||
|
pointInPolygon(x, y, polygon) {
|
||||||
|
// 确保多边形的点数是偶数且至少有3个顶点
|
||||||
|
if (!polygon || polygon.length < 6 || polygon.length % 2 !== 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inside = false;
|
||||||
|
// 转换多边形点数为顶点数
|
||||||
|
const vertexCount = polygon.length / 2;
|
||||||
|
let j = vertexCount - 1;
|
||||||
|
|
||||||
|
for (let i = 0; i < vertexCount; j = i++) {
|
||||||
|
// 获取当前顶点和上一个顶点
|
||||||
|
const xi = polygon[i * 2];
|
||||||
|
const yi = polygon[i * 2 + 1];
|
||||||
|
const xj = polygon[j * 2];
|
||||||
|
const yj = polygon[j * 2 + 1];
|
||||||
|
|
||||||
|
// 检查点是否在边界上 - 提高精度避免浮点数误差
|
||||||
|
const onLine = this.pointOnLineSegment(x, y, xi, yi, xj, yj);
|
||||||
|
if (onLine) return true;
|
||||||
|
|
||||||
|
// 检查点是否在两个顶点之间(射线法)
|
||||||
|
if ((yi < y && yj >= y) || (yj < y && yi >= y)) {
|
||||||
|
// 计算射线与边界的交点
|
||||||
|
const slope = (xj - xi) / (yj - yi);
|
||||||
|
const intersectX = xi + (y - yi) * slope;
|
||||||
|
|
||||||
|
// 如果交点在点右侧,标记为穿越
|
||||||
|
if (x < intersectX) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inside;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加点是否在线段上的检查
|
||||||
|
pointOnLineSegment(x, y, x1, y1, x2, y2) {
|
||||||
|
// 线段的长度
|
||||||
|
const dx = x2 - x1;
|
||||||
|
const dy = y2 - y1;
|
||||||
|
const segmentLength = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
// 点到线段起点的向量
|
||||||
|
const vx = x - x1;
|
||||||
|
const vy = y - y1;
|
||||||
|
|
||||||
|
// 向量在方向上的投影
|
||||||
|
const dotProduct = vx * dx + vy * dy;
|
||||||
|
|
||||||
|
// 计算参数t (0-1之间表示在线段上)
|
||||||
|
const t = dotProduct / (segmentLength * segmentLength);
|
||||||
|
|
||||||
|
// 点在线段上
|
||||||
|
if (t >= 0 && t <= 1) {
|
||||||
|
// 计算点在线段上的位置
|
||||||
|
const projX = x1 + t * dx;
|
||||||
|
const projY = y1 + t * dy;
|
||||||
|
|
||||||
|
// 检查点与投影点的距离(容差5px)
|
||||||
|
const distance = Math.sqrt((x - projX) ** 2 + (y - projY) ** 2);
|
||||||
|
return distance < 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
initCanvas() {
|
initCanvas() {
|
||||||
const query = uni.createSelectorQuery().in(this);
|
const query = uni.createSelectorQuery().in(this);
|
||||||
query.select('#myCanvas')
|
query.select('#myCanvas')
|
||||||
@ -108,10 +224,19 @@ export default {
|
|||||||
this.redraw();
|
this.redraw();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadImage(src) {
|
async loadImage(src) {
|
||||||
try {
|
try {
|
||||||
|
// 等待canvas初始化
|
||||||
|
if (!this.canvas) {
|
||||||
|
await this.initCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
this.image = await new Promise((resolve, reject) => {
|
this.image = await new Promise((resolve, reject) => {
|
||||||
|
if (!this.canvas) {
|
||||||
|
// reject(new Error("Canvas not initialized"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const image = this.canvas.createImage();
|
const image = this.canvas.createImage();
|
||||||
image.src = src;
|
image.src = src;
|
||||||
image.onload = () => resolve(image);
|
image.onload = () => resolve(image);
|
||||||
@ -121,9 +246,24 @@ export default {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("图片加载失败:", e);
|
console.error("图片加载失败:", e);
|
||||||
this.image = null;
|
this.image = null;
|
||||||
this.redraw(); // 加载失败时也需要重绘画布
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// async loadImage(src) {
|
||||||
|
// try {
|
||||||
|
// this.image = await new Promise((resolve, reject) => {
|
||||||
|
// const image = this.canvas.createImage();
|
||||||
|
// image.src = src;
|
||||||
|
// image.onload = () => resolve(image);
|
||||||
|
// image.onerror = reject;
|
||||||
|
// });
|
||||||
|
// this.redraw();
|
||||||
|
// } catch (e) {
|
||||||
|
// console.error("图片加载失败:", e);
|
||||||
|
// this.image = null;
|
||||||
|
// this.redraw(); // 加载失败时也需要重绘画布
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
redraw() {
|
redraw() {
|
||||||
if (!this.ctx) return;
|
if (!this.ctx) return;
|
||||||
@ -133,7 +273,6 @@ export default {
|
|||||||
|
|
||||||
// 重置为初始状态
|
// 重置为初始状态
|
||||||
this.ctx.resetTransform();
|
this.ctx.resetTransform();
|
||||||
console.log(this.canvasActualWidth, this.canvasActualHeight,'123123123123')
|
|
||||||
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
||||||
|
|
||||||
// 应用设备像素比缩放
|
// 应用设备像素比缩放
|
||||||
@ -152,18 +291,34 @@ export default {
|
|||||||
this.canvasDisplayWidth,
|
this.canvasDisplayWidth,
|
||||||
this.canvasDisplayHeight
|
this.canvasDisplayHeight
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
// 图片加载失败的占位图
|
// this.ctx.restore();
|
||||||
// this.ctx.fillStyle = '#f0f0f0';
|
|
||||||
// this.ctx.fillRect(0, 0, this.width, this.height);
|
|
||||||
// this.ctx.fillStyle = '#999';
|
|
||||||
// this.ctx.textAlign = 'center';
|
|
||||||
// this.ctx.textBaseline = 'middle';
|
|
||||||
// this.ctx.fillText('图片加载失败', this.width / 2, this.height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 恢复上下文状态
|
// 恢复上下文状态
|
||||||
this.ctx.restore();
|
if (this.areaData && this.areaData.length > 0) {
|
||||||
|
this.areaData.forEach(area => {
|
||||||
|
// if (!area.polygon || area.polygon.length < 6) return;
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
|
||||||
|
for (let i = 0; i < area.polygon.length; i += 2) {
|
||||||
|
// 使用标准API
|
||||||
|
if (i === 0) {
|
||||||
|
this.ctx.moveTo(area.polygon[i], area.polygon[i + 1]);
|
||||||
|
} else {
|
||||||
|
this.ctx.lineTo(area.polygon[i], area.polygon[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.closePath();
|
||||||
|
this.ctx.strokeStyle = 'rgba(255, 0, 0, 0.7)';
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.stroke();
|
||||||
|
this.ctx.fillStyle = 'rgba(0, 255, 0, 0.2)';
|
||||||
|
this.ctx.fill();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,29 @@ class TransformMatrix {
|
|||||||
clone.ty = this.ty;
|
clone.ty = this.ty;
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
// 添加点坐标转换方法
|
||||||
|
transformPoint(x, y) {
|
||||||
|
return {
|
||||||
|
x: this.a * x + this.c * y + this.tx,
|
||||||
|
y: this.b * x + this.d * y + this.ty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加逆矩阵转换方法
|
||||||
|
invertPoint(x, y) {
|
||||||
|
const det = this.a * this.d - this.b * this.c;
|
||||||
|
|
||||||
|
// 确保行列式不为零
|
||||||
|
if (Math.abs(det) < 0.0001) {
|
||||||
|
return {x, y}; // 避免除以零的错误
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用正确的逆变换公式
|
||||||
|
return {
|
||||||
|
x: (this.d * (x - this.tx) - this.c * (y - this.ty)) / det,
|
||||||
|
y: (this.a * (y - this.ty) - this.b * (x - this.tx)) / det
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TransformMatrix;
|
export default TransformMatrix;
|
File diff suppressed because one or more lines are too long
@ -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
@ -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;"}
|
@ -1 +1 @@
|
|||||||
{"version":3,"file":"transform-matrix.js","sources":["pages/index/transform-matrix.js"],"sourcesContent":["class TransformMatrix {\n constructor() {\n this.reset();\n }\n \n reset() {\n this.a = 1; // 水平缩放\n this.b = 0; // 垂直倾斜\n this.c = 0; // 水平倾斜\n this.d = 1; // 垂直缩放\n this.tx = 0; // 水平移动\n this.ty = 0; // 垂直移动\n this.stack = [];\n }\n \n translate(dx, dy) {\n this.tx += this.a * dx + this.c * dy;\n this.ty += this.b * dx + this.d * dy;\n }\n \n scale(sx, sy, cx = 0, cy = 0) {\n // 移动到中心点\n this.translate(cx, cy);\n \n // 应用缩放\n this.a *= sx;\n this.b *= sx;\n this.c *= sy;\n this.d *= sy;\n \n // 移回原位置\n this.translate(-cx, -cy);\n }\n \n toArray() {\n return [this.a, this.b, this.c, this.d, this.tx, this.ty];\n }\n \n // 用于调试的字符串表示\n toString() {\n return `[${this.a.toFixed(2)}, ${this.b.toFixed(2)}, ${this.c.toFixed(2)}, ${this.d.toFixed(2)}, ${this.tx.toFixed(1)}, ${this.ty.toFixed(1)}]`;\n }\n \n // 克隆方法\n clone() {\n const clone = new TransformMatrix();\n clone.a = this.a;\n clone.b = this.b;\n clone.c = this.c;\n clone.d = this.d;\n clone.tx = this.tx;\n clone.ty = this.ty;\n return clone;\n }\n}\n\nexport default TransformMatrix;"],"names":[],"mappings":";AAAA,MAAM,gBAAgB;AAAA,EACpB,cAAc;AACZ,SAAK,MAAK;AAAA,EACX;AAAA,EAED,QAAQ;AACN,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,QAAQ;EACd;AAAA,EAED,UAAU,IAAI,IAAI;AAChB,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI;AAClC,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI;AAAA,EACnC;AAAA,EAED,MAAM,IAAI,IAAI,KAAK,GAAG,KAAK,GAAG;AAE5B,SAAK,UAAU,IAAI,EAAE;AAGrB,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AAGV,SAAK,UAAU,CAAC,IAAI,CAAC,EAAE;AAAA,EACxB;AAAA,EAED,UAAU;AACR,WAAO,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,IAAI,KAAK,EAAE;AAAA,EACzD;AAAA;AAAA,EAGD,WAAW;AACT,WAAO,IAAI,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,CAAC;AAAA,EAC7I;AAAA;AAAA,EAGD,QAAQ;AACN,UAAM,QAAQ,IAAI;AAClB,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,WAAO;AAAA,EACR;AACH;;"}
|
{"version":3,"file":"transform-matrix.js","sources":["pages/index/transform-matrix.js"],"sourcesContent":["class TransformMatrix {\n constructor() {\n this.reset();\n }\n \n reset() {\n this.a = 1; // 水平缩放\n this.b = 0; // 垂直倾斜\n this.c = 0; // 水平倾斜\n this.d = 1; // 垂直缩放\n this.tx = 0; // 水平移动\n this.ty = 0; // 垂直移动\n this.stack = [];\n }\n \n translate(dx, dy) {\n this.tx += this.a * dx + this.c * dy;\n this.ty += this.b * dx + this.d * dy;\n }\n \n scale(sx, sy, cx = 0, cy = 0) {\n // 移动到中心点\n this.translate(cx, cy);\n \n // 应用缩放\n this.a *= sx;\n this.b *= sx;\n this.c *= sy;\n this.d *= sy;\n \n // 移回原位置\n this.translate(-cx, -cy);\n }\n \n toArray() {\n return [this.a, this.b, this.c, this.d, this.tx, this.ty];\n }\n \n // 用于调试的字符串表示\n toString() {\n return `[${this.a.toFixed(2)}, ${this.b.toFixed(2)}, ${this.c.toFixed(2)}, ${this.d.toFixed(2)}, ${this.tx.toFixed(1)}, ${this.ty.toFixed(1)}]`;\n }\n \n // 克隆方法\n clone() {\n const clone = new TransformMatrix();\n clone.a = this.a;\n clone.b = this.b;\n clone.c = this.c;\n clone.d = this.d;\n clone.tx = this.tx;\n clone.ty = this.ty;\n return clone;\n }\n\t// 添加点坐标转换方法\n\ttransformPoint(x, y) {\n\t\treturn {\n\t\t\tx: this.a * x + this.c * y + this.tx,\n\t\t\ty: this.b * x + this.d * y + this.ty\n\t\t};\n\t}\n\t\n\t// 添加逆矩阵转换方法\n\tinvertPoint(x, y) {\n\t\tconst det = this.a * this.d - this.b * this.c;\n\t\t\n\t\t// 确保行列式不为零\n\t\tif (Math.abs(det) < 0.0001) {\n\t\t\treturn {x, y}; // 避免除以零的错误\n\t\t}\n\t\t\n\t\t// 使用正确的逆变换公式\n\t\treturn {\n\t\t\tx: (this.d * (x - this.tx) - this.c * (y - this.ty)) / det,\n\t\t\ty: (this.a * (y - this.ty) - this.b * (x - this.tx)) / det\n\t\t};\n\t}\n}\n\nexport default TransformMatrix;"],"names":[],"mappings":";AAAA,MAAM,gBAAgB;AAAA,EACpB,cAAc;AACZ,SAAK,MAAK;AAAA,EACX;AAAA,EAED,QAAQ;AACN,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,IAAI;AACT,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,QAAQ;EACd;AAAA,EAED,UAAU,IAAI,IAAI;AAChB,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI;AAClC,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI;AAAA,EACnC;AAAA,EAED,MAAM,IAAI,IAAI,KAAK,GAAG,KAAK,GAAG;AAE5B,SAAK,UAAU,IAAI,EAAE;AAGrB,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AAGV,SAAK,UAAU,CAAC,IAAI,CAAC,EAAE;AAAA,EACxB;AAAA,EAED,UAAU;AACR,WAAO,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,IAAI,KAAK,EAAE;AAAA,EACzD;AAAA;AAAA,EAGD,WAAW;AACT,WAAO,IAAI,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,CAAC,KAAK,KAAK,GAAG,QAAQ,CAAC,CAAC;AAAA,EAC7I;AAAA;AAAA,EAGD,QAAQ;AACN,UAAM,QAAQ,IAAI;AAClB,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,KAAK;AACf,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,WAAO;AAAA,EACR;AAAA;AAAA,EAEF,eAAe,GAAG,GAAG;AACpB,WAAO;AAAA,MACN,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK;AAAA,MAClC,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK;AAAA,IACrC;AAAA,EACE;AAAA;AAAA,EAGD,YAAY,GAAG,GAAG;AACjB,UAAM,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK;AAG5C,QAAI,KAAK,IAAI,GAAG,IAAI,MAAQ;AAC3B,aAAO,EAAC,GAAG,EAAC;AAAA,IACZ;AAGD,WAAO;AAAA,MACN,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,OAAO;AAAA,MACvD,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,OAAO;AAAA,IAC1D;AAAA,EACE;AACF;;"}
|
11
unpackage/dist/dev/mp-weixin/common/vendor.js
vendored
11
unpackage/dist/dev/mp-weixin/common/vendor.js
vendored
@ -6880,9 +6880,9 @@ function initOnError() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
function initRuntimeSocketService() {
|
function initRuntimeSocketService() {
|
||||||
const hosts = "127.0.0.1,172.10.0.226";
|
const hosts = "127.0.0.1,172.10.0.127";
|
||||||
const port = "8090";
|
const port = "8090";
|
||||||
const id = "mp-weixin_YSvwpn";
|
const id = "mp-weixin_IDV0HS";
|
||||||
const lazy = typeof swan !== "undefined";
|
const lazy = typeof swan !== "undefined";
|
||||||
let restoreError = lazy ? () => {
|
let restoreError = lazy ? () => {
|
||||||
} : initOnError();
|
} : initOnError();
|
||||||
@ -8262,13 +8262,18 @@ class i extends l$1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.STATE_POSSIBLE = 0, i.STATE_START = 4, i.STATE_MOVE = 5, i.STATE_END = 1, i.STATE_CANCELLED = 3, i.STATE_FAILED = 2, i.STATE_RECOGNIZED = 1, i.tap = r$2, i.pan = u, i.swipe = a, i.press = c, i.rotate = i$1, i.pinch = r, i.doubletap = e;
|
i.STATE_POSSIBLE = 0, i.STATE_START = 4, i.STATE_MOVE = 5, i.STATE_END = 1, i.STATE_CANCELLED = 3, i.STATE_FAILED = 2, i.STATE_RECOGNIZED = 1, i.tap = r$2, i.pan = u, i.swipe = a, i.press = c, i.rotate = i$1, i.pinch = r, i.doubletap = e;
|
||||||
|
const index_es = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
||||||
|
__proto__: null,
|
||||||
|
default: i
|
||||||
|
}, Symbol.toStringTag, { value: "Module" }));
|
||||||
exports._export_sfc = _export_sfc;
|
exports._export_sfc = _export_sfc;
|
||||||
exports.createSSRApp = createSSRApp;
|
exports.createSSRApp = createSSRApp;
|
||||||
exports.i = i;
|
|
||||||
exports.index = index;
|
exports.index = index;
|
||||||
|
exports.index_es = index_es;
|
||||||
exports.o = o$2;
|
exports.o = o$2;
|
||||||
exports.p = p$4;
|
exports.p = p$4;
|
||||||
exports.resolveComponent = resolveComponent;
|
exports.resolveComponent = resolveComponent;
|
||||||
exports.sr = sr;
|
exports.sr = sr;
|
||||||
exports.t = t$2;
|
exports.t = t$2;
|
||||||
|
exports.wx$1 = wx$1;
|
||||||
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/vendor.js.map
|
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/vendor.js.map
|
||||||
|
@ -17,41 +17,29 @@ const _sfc_main = {
|
|||||||
gestureStatus: "等待手势...",
|
gestureStatus: "等待手势...",
|
||||||
scaleValue: 1,
|
scaleValue: 1,
|
||||||
touchPoints: 0,
|
touchPoints: 0,
|
||||||
lastGestureTime: 0
|
lastGestureTime: 0,
|
||||||
|
seatAreas: []
|
||||||
|
// 座位区域数据
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.getContainerPosition();
|
await this.getContainerPosition();
|
||||||
this.initGestureHandler();
|
this.initGestureHandler();
|
||||||
|
await this.loadSeatAreas();
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 独立的手势初始化方法
|
handleCanvasClick(e) {
|
||||||
initGestureHandler() {
|
if (!this.containerRect)
|
||||||
try {
|
return;
|
||||||
this.gestureHandler = new pages_index_gestureHandler.GestureHandler(this, this.transformMatrix, {
|
const x = e.detail.x - this.containerRect.left;
|
||||||
container: this.containerRect
|
const y = e.detail.y - this.containerRect.top;
|
||||||
});
|
const hitArea = this.$refs.canvasRef.checkHitArea(x, y);
|
||||||
} catch (e) {
|
common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:82", "hitArea", hitArea);
|
||||||
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:77", "手势处理器初始化失败:", e);
|
if (hitArea) {
|
||||||
this.gestureHandler = {
|
common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:84", "点击区域:", hitArea);
|
||||||
catchEvent: (event) => {
|
|
||||||
if (event.touches.length > 0) {
|
|
||||||
const firstTouch = event.touches[0];
|
|
||||||
const x = firstTouch.clientX - this.containerRect.left;
|
|
||||||
const y = firstTouch.clientY - this.containerRect.top;
|
|
||||||
this.gestureStatus = "降级模式: 单指拖动";
|
|
||||||
this.touchPoints = event.touches.length;
|
|
||||||
if (event.type === "touchmove") {
|
|
||||||
this.transformMatrix.tx = x;
|
|
||||||
this.transformMatrix.ty = y;
|
|
||||||
this.updateCanvas();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getContainerPosition() {
|
async getContainerPosition() {
|
||||||
@ -72,50 +60,58 @@ const _sfc_main = {
|
|||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height
|
height: rect.height
|
||||||
};
|
};
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:124", "成功获取容器位置:", this.containerRect);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:128", "获取容器位置失败:", e);
|
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:113", "获取容器位置失败:", e);
|
||||||
}
|
}
|
||||||
await new Promise((r) => setTimeout(r, 100));
|
await new Promise((r) => setTimeout(r, 100));
|
||||||
retryCount++;
|
retryCount++;
|
||||||
}
|
}
|
||||||
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:136", `容器位置获取失败,已重试${maxRetries}次`);
|
},
|
||||||
|
initGestureHandler() {
|
||||||
|
try {
|
||||||
|
this.gestureHandler = new pages_index_gestureHandler.GestureHandler(this, this.transformMatrix, {
|
||||||
|
container: this.containerRect
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:128", "手势处理器初始化失败:", 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) {
|
async handleTouchEvent(event) {
|
||||||
if (!this.gestureHandler || !this.containerRect) {
|
if (!this.gestureHandler || !this.containerRect) {
|
||||||
common_vendor.index.__f__("warn", "at pages/index/gesture-canvas-page.vue:142", "手势处理器未就绪,尝试重新初始化...");
|
|
||||||
await this.getContainerPosition();
|
await this.getContainerPosition();
|
||||||
this.initGestureHandler();
|
this.initGestureHandler();
|
||||||
if (event.type === "touchend" || event.type === "touchcancel") {
|
if (event.type === "touchend" || event.type === "touchcancel") {
|
||||||
this.lastPoint = null;
|
|
||||||
this.lastPoints = null;
|
|
||||||
this.gestureStatus = "结束";
|
this.gestureStatus = "结束";
|
||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.gestureHandler.catchEvent(event);
|
|
||||||
if (!this.at) {
|
|
||||||
if (correctedEvent.touches.length === 1) {
|
|
||||||
this.handlePan(correctedEvent.touches[0]);
|
|
||||||
} else if (correctedEvent.touches.length > 1) {
|
|
||||||
this.handlePinch(correctedEvent.touches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
this.touchPoints = event.touches.length;
|
this.touchPoints = event.touches.length;
|
||||||
const correctedTouches = Array.from(event.touches).map((touch) => {
|
const correctedTouches = Array.from(event.touches).map((touch) => {
|
||||||
const x = touch.clientX - this.containerRect.left;
|
|
||||||
const y = touch.clientY - this.containerRect.top;
|
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-canvas-page.vue:181", `原始坐标: (${touch.clientX}, ${touch.clientY}) 修正后: (${x}, ${y})`);
|
|
||||||
return {
|
return {
|
||||||
...touch,
|
...touch,
|
||||||
x,
|
x: touch.clientX - this.containerRect.left,
|
||||||
y
|
y: touch.clientY - this.containerRect.top
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const correctedEvent = {
|
const correctedEvent = {
|
||||||
@ -136,15 +132,12 @@ const _sfc_main = {
|
|||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 更新Canvas(性能优化版)
|
// 更新Canvas
|
||||||
updateCanvas() {
|
updateCanvas() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const canvas = this.$refs.canvasRef;
|
this.scaleValue = Math.sqrt(
|
||||||
if (canvas) {
|
this.transformMatrix.a * this.transformMatrix.a + this.transformMatrix.b * this.transformMatrix.b
|
||||||
this.scaleValue = Math.sqrt(
|
);
|
||||||
this.transformMatrix.a * this.transformMatrix.a + this.transformMatrix.b * this.transformMatrix.b
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 重置画布
|
// 重置画布
|
||||||
@ -163,6 +156,19 @@ const _sfc_main = {
|
|||||||
zoomOut() {
|
zoomOut() {
|
||||||
this.transformMatrix.scale(0.8, 0.8, this.canvasWidth / 2, this.canvasHeight / 2);
|
this.transformMatrix.scale(0.8, 0.8, this.canvasWidth / 2, this.canvasHeight / 2);
|
||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
|
},
|
||||||
|
// 加载座位区域数据
|
||||||
|
async loadSeatAreas() {
|
||||||
|
try {
|
||||||
|
const response = {
|
||||||
|
"code": 200,
|
||||||
|
"message": "",
|
||||||
|
"data": [{ "areacode": "03tkrrjukrgu", "areaname": "主席台", "description": "主席台", "remain": 100, "polygon": [262, 154, 262, 165, 262, 177, 262, 188, 314, 188, 365, 188, 417, 188, 417, 177, 417, 165, 417, 154, 365, 154, 314, 154, 262, 154] }, { "areacode": "ea0jg3jukrgw", "areaname": "A区", "description": "A区", "remain": 1e3, "polygon": [105, 94, 105, 125, 105, 158, 105, 189, 183, 189, 251, 189, 250, 147, 336, 147, 337, 125, 337, 94, 259, 94, 183, 94, 105, 94] }, { "areacode": "832fe6ej0kqc", "areaname": "C区", "description": "C区", "remain": 1e3, "polygon": [106, 418, 106, 452, 106, 487, 106, 521, 183, 521, 261, 521, 338, 521, 338, 487, 338, 452, 338, 418, 261, 418, 183, 418, 106, 418] }, { "areacode": "p5naxqej0kqd", "areaname": "B区", "description": "B区", "remain": 1e3, "polygon": [345, 93, 345, 125, 344, 147, 425, 148, 425, 188, 499, 190, 576, 190, 576, 158, 576, 125, 576, 93, 499, 93, 422, 93, 345, 93] }, { "areacode": "uknpk3sa819j", "areaname": "D区", "description": "D区", "remain": 1e3, "polygon": [347, 419, 347, 453, 347, 487, 347, 521, 423, 521, 499, 521, 575, 521, 575, 487, 575, 453, 575, 419, 499, 419, 423, 419, 347, 419] }]
|
||||||
|
};
|
||||||
|
this.seatAreas = response.data;
|
||||||
|
} catch (e) {
|
||||||
|
common_vendor.index.__f__("error", "at pages/index/gesture-canvas-page.vue:248", "加载区域数据失败:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -182,15 +188,14 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|||||||
width: $data.canvasWidth,
|
width: $data.canvasWidth,
|
||||||
height: $data.canvasHeight,
|
height: $data.canvasHeight,
|
||||||
matrix: $data.transformMatrix,
|
matrix: $data.transformMatrix,
|
||||||
imgUrl: "https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg"
|
imgUrl: "https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg",
|
||||||
|
areaData: $data.seatAreas
|
||||||
}),
|
}),
|
||||||
h: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
h: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
||||||
i: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
i: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
||||||
j: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
j: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
||||||
k: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
k: common_vendor.o((...args) => $options.handleTouchEvent && $options.handleTouchEvent(...args)),
|
||||||
l: common_vendor.o((...args) => $options.resetCanvas && $options.resetCanvas(...args)),
|
l: common_vendor.o((...args) => $options.handleCanvasClick && $options.handleCanvasClick(...args))
|
||||||
m: common_vendor.o((...args) => $options.zoomIn && $options.zoomIn(...args)),
|
|
||||||
n: common_vendor.o((...args) => $options.zoomOut && $options.zoomOut(...args))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-2e633000"]]);
|
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-2e633000"]]);
|
||||||
|
@ -1 +1 @@
|
|||||||
<view class="container data-v-2e633000"><view class="gesture-container data-v-2e633000" bindtouchstart="{{h}}" bindtouchmove="{{i}}" bindtouchend="{{j}}" bindtouchcancel="{{k}}"><view class="debug-info data-v-2e633000"><text class="data-v-2e633000">缩放: {{a}} | X: {{b}} | Y: {{c}}</text><text class="data-v-2e633000">手势: {{d}}</text><text class="data-v-2e633000">触点: {{e}}</text></view><transform-canvas wx:if="{{g}}" class="r data-v-2e633000" u-r="canvasRef" u-i="2e633000-0" bind:__l="__l" u-p="{{g}}"/></view><view class="controls data-v-2e633000"><button class="data-v-2e633000" bindtap="{{l}}">重置</button><button class="data-v-2e633000" bindtap="{{m}}">放大</button><button class="data-v-2e633000" bindtap="{{n}}">缩小</button></view></view>
|
<view class="container data-v-2e633000" bindtap="{{l}}"><view class="gesture-container data-v-2e633000" bindtouchstart="{{h}}" bindtouchmove="{{i}}" bindtouchend="{{j}}" bindtouchcancel="{{k}}"><view class="debug-info data-v-2e633000"><text class="data-v-2e633000">缩放: {{a}} | X: {{b}} | Y: {{c}}</text><text class="data-v-2e633000">手势: {{d}}</text><text class="data-v-2e633000">触点: {{e}}</text></view><transform-canvas wx:if="{{g}}" class="r data-v-2e633000" u-r="canvasRef" u-i="2e633000-0" bind:__l="__l" u-p="{{g}}"/></view></view>
|
@ -1,12 +1,11 @@
|
|||||||
|
|
||||||
.container.data-v-2e633000 {
|
.container.data-v-2e633000 {
|
||||||
padding: 20px;
|
/* padding: 20px; */
|
||||||
}
|
}
|
||||||
.gesture-container.data-v-2e633000 {
|
.gesture-container.data-v-2e633000 {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 300px;
|
width: 100%;
|
||||||
height: 300px;
|
/* height: 70vh; */
|
||||||
border: 1px solid #ccc;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
.debug-info.data-v-2e633000 {
|
.debug-info.data-v-2e633000 {
|
||||||
|
@ -6,60 +6,97 @@ class GestureHandler {
|
|||||||
this.containerRect = container;
|
this.containerRect = container;
|
||||||
this.panThreshold = 5;
|
this.panThreshold = 5;
|
||||||
this.panStarted = false;
|
this.panStarted = false;
|
||||||
const atOptions = {
|
this.isMiniProgram = typeof common_vendor.wx$1 !== "undefined" || typeof common_vendor.index !== "undefined";
|
||||||
getPoint: (touch) => ({
|
if (this.isMiniProgram) {
|
||||||
x: touch.clientX - this.containerRect.left,
|
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:13", "小程序环境,使用降级手势处理器");
|
||||||
y: touch.clientY - this.containerRect.top
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
}),
|
return;
|
||||||
preventDefault: false
|
}
|
||||||
};
|
try {
|
||||||
if (typeof window === "undefined" || typeof HTMLElement === "undefined") {
|
const atOptions = {
|
||||||
atOptions._element = {
|
getPoint: (touch) => ({
|
||||||
|
x: touch.clientX - this.containerRect.left,
|
||||||
|
y: touch.clientY - this.containerRect.top
|
||||||
|
}),
|
||||||
|
preventDefault: false
|
||||||
|
};
|
||||||
|
atOptions.element = {
|
||||||
style: {},
|
style: {},
|
||||||
addEventListener: () => {
|
addEventListener: () => {
|
||||||
},
|
},
|
||||||
removeEventListener: () => {
|
removeEventListener: () => {
|
||||||
|
},
|
||||||
|
ownerDocument: {
|
||||||
|
documentElement: {
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
"../../common/vendor.js".then((n) => n.index_es).then((AnyTouch) => {
|
||||||
try {
|
this.at = new AnyTouch.default(atOptions);
|
||||||
this.at = new common_vendor.i(atOptions);
|
this.setupGestures();
|
||||||
|
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:44", "AnyTouch手势处理器已初始化");
|
||||||
|
}).catch((e) => {
|
||||||
|
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:46", "AnyTouch加载失败:", e);
|
||||||
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:32", "AnyTouch初始化失败:", e);
|
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:50", "AnyTouch初始化失败:", e);
|
||||||
this.handleGesture = this.createSimpleGestureHandler();
|
this.catchEvent = this.createSimpleGestureHandler();
|
||||||
}
|
|
||||||
if (this.at) {
|
|
||||||
this.setupGestures();
|
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:39", "AnyTouch手势处理器已初始化");
|
|
||||||
} else {
|
|
||||||
common_vendor.index.__f__("warn", "at pages/index/gesture-handler.js:41", "使用简化手势处理器");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 创建小程序专用的简化手势处理器
|
// 创建小程序专用的简化手势处理器
|
||||||
createSimpleGestureHandler() {
|
createSimpleGestureHandler() {
|
||||||
return {
|
let isClick = true;
|
||||||
run: (event) => {
|
let startPoint = null;
|
||||||
const touches = event.touches || [];
|
let startTime = null;
|
||||||
if (touches.length === 1) {
|
let lastPoint = null;
|
||||||
this._handlePan(touches[0]);
|
return (event) => {
|
||||||
} else if (touches.length > 1) {
|
const touches = event.touches || [];
|
||||||
this._handlePinch(touches);
|
if (touches.length === 1) {
|
||||||
|
const getPoint = (t2) => ({
|
||||||
|
x: t2.x || t2.clientX - this.containerRect.left,
|
||||||
|
y: t2.y || t2.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() {
|
setupGestures() {
|
||||||
this.at.on("pan", (event) => {
|
this.at.on("pan", (event) => {
|
||||||
if (event.type === "panstart") {
|
if (event.type === "panstart") {
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:67", "panstart", event);
|
|
||||||
this.panStarted = false;
|
this.panStarted = false;
|
||||||
} else if (event.type === "panmove") {
|
} else if (event.type === "panmove") {
|
||||||
const distance = Math.sqrt(event.deltaX ** 2 + event.deltaY ** 2);
|
const distance = Math.sqrt(event.deltaX ** 2 + event.deltaY ** 2);
|
||||||
if (!this.panStarted && distance < this.panThreshold) {
|
if (!this.panStarted && distance < this.panThreshold)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (!this.panStarted) {
|
if (!this.panStarted) {
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:80", "拖动手势开始");
|
|
||||||
this.panStarted = true;
|
this.panStarted = true;
|
||||||
}
|
}
|
||||||
const currentScale = Math.sqrt(
|
const currentScale = Math.sqrt(
|
||||||
@ -67,7 +104,6 @@ class GestureHandler {
|
|||||||
);
|
);
|
||||||
const dx = event.deltaX / currentScale;
|
const dx = event.deltaX / currentScale;
|
||||||
const dy = event.deltaY / currentScale;
|
const dy = event.deltaY / currentScale;
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:95", `平移: deltaX=${event.deltaX}, deltaY=${event.deltaY} | 修正后: dx=${dx}, dy=${dy}`);
|
|
||||||
this.transformMatrix.translate(dx, dy);
|
this.transformMatrix.translate(dx, dy);
|
||||||
} else if (event.type === "panend") {
|
} else if (event.type === "panend") {
|
||||||
this.panStarted = false;
|
this.panStarted = false;
|
||||||
@ -81,45 +117,27 @@ class GestureHandler {
|
|||||||
this.lastScale = event.scale;
|
this.lastScale = event.scale;
|
||||||
const centerX = event.center.x;
|
const centerX = event.center.x;
|
||||||
const centerY = event.center.y;
|
const centerY = event.center.y;
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:117", `缩放: scale=${event.scale} | 变化=${scaleChange} | 中心点: (${centerX}, ${centerY})`);
|
|
||||||
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.at.on("tap", (event) => {
|
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:126", "点击事件", event);
|
|
||||||
});
|
|
||||||
this.at.on("press", (event) => {
|
|
||||||
common_vendor.index.__f__("log", "at pages/index/gesture-handler.js:131", "长按事件", event);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// 公共接口保持不变
|
// 公共接口
|
||||||
catchEvent(event) {
|
catchEvent(event) {
|
||||||
try {
|
try {
|
||||||
if (this.at) {
|
if (this.at) {
|
||||||
this.at.run(event);
|
this.at.run(event);
|
||||||
} else {
|
} else if (this.catchEvent) {
|
||||||
const touches = event.touches || [];
|
this.catchEvent(event);
|
||||||
const eventType = event.type;
|
|
||||||
if (eventType === "touchstart") {
|
|
||||||
this.lastPoint = null;
|
|
||||||
this.lastPoints = null;
|
|
||||||
this.lastDistance = null;
|
|
||||||
}
|
|
||||||
if (touches.length === 1) {
|
|
||||||
this._handlePan(touches[0]);
|
|
||||||
} else if (touches.length > 1) {
|
|
||||||
this._handlePinch(touches);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:161", "手势处理错误:", e);
|
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:171", "手势处理错误:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 基础平移手势处理
|
// 基础平移手势处理
|
||||||
_handlePan(touch) {
|
_handlePan(touch) {
|
||||||
const getPoint = (t) => ({
|
const getPoint = (t2) => ({
|
||||||
x: t.x || t.clientX - this.containerRect.left,
|
x: t2.x || t2.clientX - this.containerRect.left,
|
||||||
y: t.y || t.clientY - this.containerRect.top
|
y: t2.y || t2.clientY - this.containerRect.top
|
||||||
});
|
});
|
||||||
const currentPoint = getPoint(touch);
|
const currentPoint = getPoint(touch);
|
||||||
if (this.lastPoint) {
|
if (this.lastPoint) {
|
||||||
@ -136,7 +154,7 @@ class GestureHandler {
|
|||||||
const point2 = touches[1];
|
const point2 = touches[1];
|
||||||
const getPoint = (touch) => ({
|
const getPoint = (touch) => ({
|
||||||
x: touch.x || touch.clientX - this.containerRect.left,
|
x: touch.x || touch.clientX - this.containerRect.left,
|
||||||
y: touch.y || touch.clientY - this.containerRect.top
|
y: touch.y || t.clientY - this.containerRect.top
|
||||||
});
|
});
|
||||||
const currentPoints = [getPoint(point1), getPoint(point2)];
|
const currentPoints = [getPoint(point1), getPoint(point2)];
|
||||||
if (this.lastPoints) {
|
if (this.lastPoints) {
|
||||||
|
@ -19,7 +19,8 @@ const _sfc_main = {
|
|||||||
tx: 0,
|
tx: 0,
|
||||||
ty: 0
|
ty: 0
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
areaData: {}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -67,6 +68,86 @@ const _sfc_main = {
|
|||||||
this.initCanvas();
|
this.initCanvas();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 添加点击检测方法
|
||||||
|
checkHitArea(x, y) {
|
||||||
|
if (!this.areaData)
|
||||||
|
return null;
|
||||||
|
const inverted = this.matrix.invertPoint(x, y);
|
||||||
|
common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:79", "checkHitArea", inverted);
|
||||||
|
for (const area of this.areaData) {
|
||||||
|
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
|
||||||
|
return area.areacode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
// 射线法判断点是否在多边形内
|
||||||
|
// pointInPolygon(x, y, polygon) {
|
||||||
|
// // uni.__f__('log','at pages/index/transform-canvas.vue:90','pointInPolygon',x, y, polygon)
|
||||||
|
// // 确保多边形有足够的点构成
|
||||||
|
// if (!polygon || polygon.length < 6) return false;
|
||||||
|
// let inside = false;
|
||||||
|
// const length = polygon.length;
|
||||||
|
// // 不需要遍历最后一个点,因为它是闭合点(与第一个点相同)
|
||||||
|
// for (let i = 0, j = length - 2; i < length; j = i, i += 2) {
|
||||||
|
// const xi = polygon[i], yi = polygon[i + 1];
|
||||||
|
// const xj = polygon[j], yj = polygon[j + 1];
|
||||||
|
// // 检查点是否在边的y值范围内
|
||||||
|
// const intersect = ((yi > y) !== (yj > y));
|
||||||
|
// // 检查点是否在边的左侧
|
||||||
|
// if (intersect) {
|
||||||
|
// const slope = (xj - xi) / (yj - yi); // 边的斜率
|
||||||
|
// const intersectX = xi + (y - yi) * slope;
|
||||||
|
// if (x < intersectX) {
|
||||||
|
// inside = !inside;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return inside;
|
||||||
|
// },
|
||||||
|
// 在 transform-canvas.vue 中替换 pointInPolygon 方法
|
||||||
|
pointInPolygon(x, y, polygon) {
|
||||||
|
if (!polygon || polygon.length < 6 || polygon.length % 2 !== 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let inside = false;
|
||||||
|
const vertexCount = polygon.length / 2;
|
||||||
|
let j = vertexCount - 1;
|
||||||
|
for (let i = 0; i < vertexCount; j = i++) {
|
||||||
|
const xi = polygon[i * 2];
|
||||||
|
const yi = polygon[i * 2 + 1];
|
||||||
|
const xj = polygon[j * 2];
|
||||||
|
const yj = polygon[j * 2 + 1];
|
||||||
|
const onLine = this.pointOnLineSegment(x, y, xi, yi, xj, yj);
|
||||||
|
if (onLine)
|
||||||
|
return true;
|
||||||
|
if (yi < y && yj >= y || yj < y && yi >= y) {
|
||||||
|
const slope = (xj - xi) / (yj - yi);
|
||||||
|
const intersectX = xi + (y - yi) * slope;
|
||||||
|
if (x < intersectX) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
},
|
||||||
|
// 添加点是否在线段上的检查
|
||||||
|
pointOnLineSegment(x, y, x1, y1, x2, y2) {
|
||||||
|
const dx = x2 - x1;
|
||||||
|
const dy = y2 - y1;
|
||||||
|
const segmentLength = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
const vx = x - x1;
|
||||||
|
const vy = y - y1;
|
||||||
|
const dotProduct = vx * dx + vy * dy;
|
||||||
|
const t = dotProduct / (segmentLength * segmentLength);
|
||||||
|
if (t >= 0 && t <= 1) {
|
||||||
|
const projX = x1 + t * dx;
|
||||||
|
const projY = y1 + t * dy;
|
||||||
|
const distance = Math.sqrt((x - projX) ** 2 + (y - projY) ** 2);
|
||||||
|
return distance < 5;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
initCanvas() {
|
initCanvas() {
|
||||||
const query = common_vendor.index.createSelectorQuery().in(this);
|
const query = common_vendor.index.createSelectorQuery().in(this);
|
||||||
query.select("#myCanvas").fields({ node: true, size: true }).exec(async (res) => {
|
query.select("#myCanvas").fields({ node: true, size: true }).exec(async (res) => {
|
||||||
@ -95,7 +176,13 @@ const _sfc_main = {
|
|||||||
},
|
},
|
||||||
async loadImage(src) {
|
async loadImage(src) {
|
||||||
try {
|
try {
|
||||||
|
if (!this.canvas) {
|
||||||
|
await this.initCanvas();
|
||||||
|
}
|
||||||
this.image = await new Promise((resolve, reject) => {
|
this.image = await new Promise((resolve, reject) => {
|
||||||
|
if (!this.canvas) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const image = this.canvas.createImage();
|
const image = this.canvas.createImage();
|
||||||
image.src = src;
|
image.src = src;
|
||||||
image.onload = () => resolve(image);
|
image.onload = () => resolve(image);
|
||||||
@ -103,17 +190,30 @@ const _sfc_main = {
|
|||||||
});
|
});
|
||||||
this.redraw();
|
this.redraw();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:122", "图片加载失败:", e);
|
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:247", "图片加载失败:", e);
|
||||||
this.image = null;
|
this.image = null;
|
||||||
this.redraw();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// async loadImage(src) {
|
||||||
|
// try {
|
||||||
|
// this.image = await new Promise((resolve, reject) => {
|
||||||
|
// const image = this.canvas.createImage();
|
||||||
|
// image.src = src;
|
||||||
|
// image.onload = () => resolve(image);
|
||||||
|
// image.onerror = reject;
|
||||||
|
// });
|
||||||
|
// this.redraw();
|
||||||
|
// } catch (e) {
|
||||||
|
// uni.__f__('error','at pages/index/transform-canvas.vue:262',"图片加载失败:", e);
|
||||||
|
// this.image = null;
|
||||||
|
// this.redraw(); // 加载失败时也需要重绘画布
|
||||||
|
// }
|
||||||
|
// },
|
||||||
redraw() {
|
redraw() {
|
||||||
if (!this.ctx)
|
if (!this.ctx)
|
||||||
return;
|
return;
|
||||||
this.ctx.save();
|
this.ctx.save();
|
||||||
this.ctx.resetTransform();
|
this.ctx.resetTransform();
|
||||||
common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:136", this.canvasActualWidth, this.canvasActualHeight, "123123123123");
|
|
||||||
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
||||||
this.ctx.scale(this.dpr, this.dpr);
|
this.ctx.scale(this.dpr, this.dpr);
|
||||||
const { a, b, c, d, tx, ty } = this.matrix;
|
const { a, b, c, d, tx, ty } = this.matrix;
|
||||||
@ -127,7 +227,24 @@ const _sfc_main = {
|
|||||||
this.canvasDisplayHeight
|
this.canvasDisplayHeight
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.ctx.restore();
|
if (this.areaData && this.areaData.length > 0) {
|
||||||
|
this.areaData.forEach((area) => {
|
||||||
|
this.ctx.beginPath();
|
||||||
|
for (let i = 0; i < area.polygon.length; i += 2) {
|
||||||
|
if (i === 0) {
|
||||||
|
this.ctx.moveTo(area.polygon[i], area.polygon[i + 1]);
|
||||||
|
} else {
|
||||||
|
this.ctx.lineTo(area.polygon[i], area.polygon[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ctx.closePath();
|
||||||
|
this.ctx.strokeStyle = "rgba(255, 0, 0, 0.7)";
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.stroke();
|
||||||
|
this.ctx.fillStyle = "rgba(0, 255, 0, 0.2)";
|
||||||
|
this.ctx.fill();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,24 @@ class TransformMatrix {
|
|||||||
clone.ty = this.ty;
|
clone.ty = this.ty;
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
// 添加点坐标转换方法
|
||||||
|
transformPoint(x, y) {
|
||||||
|
return {
|
||||||
|
x: this.a * x + this.c * y + this.tx,
|
||||||
|
y: this.b * x + this.d * y + this.ty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 添加逆矩阵转换方法
|
||||||
|
invertPoint(x, y) {
|
||||||
|
const det = this.a * this.d - this.b * this.c;
|
||||||
|
if (Math.abs(det) < 1e-4) {
|
||||||
|
return { x, y };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: (this.d * (x - this.tx) - this.c * (y - this.ty)) / det,
|
||||||
|
y: (this.a * (y - this.ty) - this.b * (x - this.tx)) / det
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.TransformMatrix = TransformMatrix;
|
exports.TransformMatrix = TransformMatrix;
|
||||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/transform-matrix.js.map
|
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/transform-matrix.js.map
|
||||||
|
Loading…
x
Reference in New Issue
Block a user