选区选座
This commit is contained in:
parent
40437fd728
commit
a0129fa7ce
File diff suppressed because one or more lines are too long
@ -161,6 +161,13 @@ class GestureHandler {
|
||||
|
||||
// 公共接口
|
||||
catchEvent(event) {
|
||||
// 当触摸点数量变化时终止当前手势
|
||||
if (this.lastTouchCount !== event.touches.length) {
|
||||
this.panStarted = false;
|
||||
this.lastPoints = null;
|
||||
}
|
||||
this.lastTouchCount = event.touches.length;
|
||||
|
||||
try {
|
||||
if (this.at) {
|
||||
this.at.run(event);
|
||||
|
@ -26,7 +26,8 @@ export default {
|
||||
a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
|
||||
})
|
||||
},
|
||||
areaData:{}
|
||||
areaData:{},
|
||||
seatData:{}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -65,6 +66,18 @@ export default {
|
||||
this.$nextTick(this.redraw); // 确保在下一个tick重绘
|
||||
}
|
||||
},
|
||||
areaData: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$nextTick(this.redraw);
|
||||
}
|
||||
},
|
||||
seatData: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$nextTick(this.redraw);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initCanvas();
|
||||
@ -75,77 +88,37 @@ export default {
|
||||
if (!this.areaData) return null;
|
||||
|
||||
// 转换坐标到原始画布空间
|
||||
const inverted = this.matrix.invertPoint(x, y);
|
||||
const inverted = this.matrix.invertPoint(x, y, this.dpr);
|
||||
console.log('checkHitArea',inverted)
|
||||
// 遍历所有区域检测
|
||||
for (const area of this.areaData) {
|
||||
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
|
||||
return area.areacode;
|
||||
return area;
|
||||
}
|
||||
}
|
||||
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;
|
||||
const points = [];
|
||||
for (let i = 0; i < polygon.length; i += 2) {
|
||||
points.push([polygon[i], polygon[i + 1]]);
|
||||
}
|
||||
|
||||
let inside = false;
|
||||
// 转换多边形点数为顶点数
|
||||
const vertexCount = polygon.length / 2;
|
||||
let j = vertexCount - 1;
|
||||
let j = points.length - 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];
|
||||
for (let i = 0; i < points.length; j = i++) {
|
||||
const [xi, yi] = points[i];
|
||||
const [xj, yj] = points[j];
|
||||
|
||||
// 检查点是否在边界上 - 提高精度避免浮点数误差
|
||||
const onLine = this.pointOnLineSegment(x, y, xi, yi, xj, yj);
|
||||
if (onLine) return true;
|
||||
// 检测点是否在线段上
|
||||
if (this.pointOnLineSegment(x, y, xi, yi, xj, yj)) return true;
|
||||
|
||||
// 检查点是否在两个顶点之间(射线法)
|
||||
if ((yi < y && yj >= y) || (yj < y && yi >= y)) {
|
||||
// 计算射线与边界的交点
|
||||
// 射线法核心逻辑
|
||||
if (yi <= y && yj > y || yj <= y && yi > y) {
|
||||
const slope = (xj - xi) / (yj - yi);
|
||||
const intersectX = xi + (y - yi) * slope;
|
||||
|
||||
// 如果交点在点右侧,标记为穿越
|
||||
if (x < intersectX) {
|
||||
if (x <= xi + (y - yi) * slope) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
@ -154,6 +127,8 @@ export default {
|
||||
return inside;
|
||||
},
|
||||
|
||||
|
||||
|
||||
// 添加点是否在线段上的检查
|
||||
pointOnLineSegment(x, y, x1, y1, x2, y2) {
|
||||
// 线段的长度
|
||||
@ -178,7 +153,7 @@ export default {
|
||||
const projY = y1 + t * dy;
|
||||
|
||||
// 检查点与投影点的距离(容差5px)
|
||||
const distance = Math.sqrt((x - projX) ** 2 + (y - projY) ** 2);
|
||||
const distance = Math.sqrt((x - projX) * 2 + (y - projY) * 2);
|
||||
return distance < 5;
|
||||
}
|
||||
|
||||
@ -212,15 +187,16 @@ export default {
|
||||
// 显示尺寸使用prop传入的width/height
|
||||
this.canvasDisplayWidth = this.width;
|
||||
this.canvasDisplayHeight = this.height;
|
||||
|
||||
// * this.dpr
|
||||
// * this.dpr
|
||||
// 实际像素尺寸考虑DPR
|
||||
this.canvasActualWidth = this.width * this.dpr;
|
||||
this.canvasActualHeight = this.height * this.dpr;
|
||||
this.canvasActualWidth = this.width;
|
||||
this.canvasActualHeight = this.height;
|
||||
|
||||
if (this.canvas) {
|
||||
this.canvas.width = this.canvasActualWidth;
|
||||
this.canvas.height = this.canvasActualHeight;
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
// this.ctx.scale(this.dpr, this.dpr);
|
||||
this.redraw();
|
||||
}
|
||||
},
|
||||
@ -249,77 +225,103 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 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方法中添加视图判断
|
||||
checkSeatHit(x, y) {
|
||||
if (!this.seatData) return null;
|
||||
|
||||
redraw() {
|
||||
if (!this.ctx) return;
|
||||
// 转换坐标到原始画布空间
|
||||
const inverted = this.matrix.invertPoint(x, y, this.dpr);
|
||||
|
||||
// 保存当前状态
|
||||
this.ctx.save();
|
||||
// 遍历所有座位检测
|
||||
for (const seat of this.seatData) {
|
||||
const dx = seat.x - inverted.x;
|
||||
const dy = seat.y - inverted.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
// 重置为初始状态
|
||||
this.ctx.resetTransform();
|
||||
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
||||
// 命中检测(8px半径)
|
||||
if (distance < 8) {
|
||||
return seat;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
redraw() {
|
||||
if (!this.ctx) return;
|
||||
|
||||
// 应用设备像素比缩放
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
this.ctx.save();
|
||||
this.ctx.resetTransform();
|
||||
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
|
||||
// 应用变换矩阵
|
||||
const { a, b, c, d, tx, ty } = this.matrix;
|
||||
this.ctx.setTransform(a, b, c, d, tx, ty);
|
||||
// 应用变换矩阵
|
||||
const { a, b, c, d, tx, ty } = this.matrix;
|
||||
this.ctx.setTransform(a, b, c, d, tx, ty);
|
||||
|
||||
// 绘制图片(或错误信息)
|
||||
if (this.image) {
|
||||
this.ctx.drawImage(
|
||||
this.image,
|
||||
0,
|
||||
0,
|
||||
this.canvasDisplayWidth,
|
||||
this.canvasDisplayHeight
|
||||
);
|
||||
}
|
||||
// this.ctx.restore();
|
||||
// 仅在区域视图显示背景图片
|
||||
if (this.image && this.$parent?.currentView === 'area') {
|
||||
this.ctx.drawImage(
|
||||
this.image,
|
||||
0,
|
||||
0,
|
||||
this.canvasDisplayWidth,
|
||||
this.canvasDisplayHeight
|
||||
);
|
||||
}
|
||||
|
||||
// 恢复上下文状态
|
||||
if (this.areaData && this.areaData.length > 0) {
|
||||
this.areaData.forEach(area => {
|
||||
// if (!area.polygon || area.polygon.length < 6) return;
|
||||
// 绘制区域(仅在区域视图)
|
||||
if (this.areaData && this.areaData.length > 0 && this.$parent?.currentView === 'area') {
|
||||
this.drawAreas();
|
||||
}
|
||||
|
||||
this.ctx.beginPath();
|
||||
// 绘制座位(仅在座位视图)
|
||||
if (this.seatData && this.seatData.length > 0 && this.$parent?.currentView === 'seat') {
|
||||
this.drawSeats();
|
||||
}
|
||||
|
||||
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.restore();
|
||||
},
|
||||
// 添加绘制区域方法
|
||||
drawAreas() {
|
||||
this.areaData.forEach(area => {
|
||||
const points = [];
|
||||
for (let i = 0; i < area.polygon.length; i += 2) {
|
||||
points.push([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();
|
||||
});
|
||||
}
|
||||
this.ctx.beginPath();
|
||||
points.forEach(([x, y], index) => {
|
||||
if (index === 0) this.ctx.moveTo(x, y);
|
||||
else this.ctx.lineTo(x, y);
|
||||
});
|
||||
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();
|
||||
});
|
||||
},
|
||||
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();
|
||||
|
||||
// 仅在缩放足够大时显示文字
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -61,20 +61,17 @@ class TransformMatrix {
|
||||
}
|
||||
|
||||
// 添加逆矩阵转换方法
|
||||
invertPoint(x, y) {
|
||||
const det = this.a * this.d - this.b * this.c;
|
||||
invertPoint(x, y, dpr) {
|
||||
console.log('invertPoint:',dpr)
|
||||
const det = this.a * this.d - this.b * this.c;
|
||||
if (Math.abs(det) < 0.0001) return {x, y};
|
||||
|
||||
// 确保行列式不为零
|
||||
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
|
||||
};
|
||||
return {
|
||||
x: (this.d * (x/dpr - this.tx) - this.c * (y/dpr - this.ty)) / det,
|
||||
y: (this.a * (y/dpr - this.ty) - this.b * (x/dpr - this.tx)) / det
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TransformMatrix;
|
@ -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\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;;"}
|
||||
{"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, dpr) {\n\t\tconsole.log('invertPoint:',dpr)\n\t const det = this.a * this.d - this.b * this.c;\n\t if (Math.abs(det) < 0.0001) return {x, y};\n\t \n\t return {\n\t x: (this.d * (x/dpr - this.tx) - this.c * (y/dpr - this.ty)) / det,\n\t y: (this.a * (y/dpr - this.ty) - this.b * (x/dpr - this.tx)) / det\n\t };\n\t}\n\t\n}\n\nexport default TransformMatrix;"],"names":["uni"],"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,KAAK;AACtBA,kBAAAA,4DAAY,gBAAe,GAAG;AAC7B,UAAM,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK;AAC5C,QAAI,KAAK,IAAI,GAAG,IAAI;AAAQ,aAAO,EAAC,GAAG,EAAC;AAExC,WAAO;AAAA,MACL,IAAI,KAAK,KAAK,IAAE,MAAM,KAAK,MAAM,KAAK,KAAK,IAAE,MAAM,KAAK,OAAO;AAAA,MAC/D,IAAI,KAAK,KAAK,IAAE,MAAM,KAAK,MAAM,KAAK,KAAK,IAAE,MAAM,KAAK,OAAO;AAAA,IACpE;AAAA,EACE;AAEF;;"}
|
@ -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_IDV0HS";
|
||||
const id = "mp-weixin_8j0jyd";
|
||||
const lazy = typeof swan !== "undefined";
|
||||
let restoreError = lazy ? () => {
|
||||
} : initOnError();
|
||||
|
File diff suppressed because one or more lines are too long
@ -123,6 +123,11 @@ class GestureHandler {
|
||||
}
|
||||
// 公共接口
|
||||
catchEvent(event) {
|
||||
if (this.lastTouchCount !== event.touches.length) {
|
||||
this.panStarted = false;
|
||||
this.lastPoints = null;
|
||||
}
|
||||
this.lastTouchCount = event.touches.length;
|
||||
try {
|
||||
if (this.at) {
|
||||
this.at.run(event);
|
||||
@ -130,7 +135,7 @@ class GestureHandler {
|
||||
this.catchEvent(event);
|
||||
}
|
||||
} catch (e) {
|
||||
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:171", "手势处理错误:", e);
|
||||
common_vendor.index.__f__("error", "at pages/index/gesture-handler.js:178", "手势处理错误:", e);
|
||||
}
|
||||
}
|
||||
// 基础平移手势处理
|
||||
|
@ -20,7 +20,8 @@ const _sfc_main = {
|
||||
ty: 0
|
||||
})
|
||||
},
|
||||
areaData: {}
|
||||
areaData: {},
|
||||
seatData: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -62,6 +63,18 @@ const _sfc_main = {
|
||||
handler() {
|
||||
this.$nextTick(this.redraw);
|
||||
}
|
||||
},
|
||||
areaData: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$nextTick(this.redraw);
|
||||
}
|
||||
},
|
||||
seatData: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$nextTick(this.redraw);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -72,59 +85,30 @@ const _sfc_main = {
|
||||
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);
|
||||
const inverted = this.matrix.invertPoint(x, y, this.dpr);
|
||||
common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:92", "checkHitArea", inverted);
|
||||
for (const area of this.areaData) {
|
||||
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
|
||||
return area.areacode;
|
||||
return area;
|
||||
}
|
||||
}
|
||||
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;
|
||||
const points = [];
|
||||
for (let i = 0; i < polygon.length; i += 2) {
|
||||
points.push([polygon[i], polygon[i + 1]]);
|
||||
}
|
||||
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)
|
||||
let j = points.length - 1;
|
||||
for (let i = 0; i < points.length; j = i++) {
|
||||
const [xi, yi] = points[i];
|
||||
const [xj, yj] = points[j];
|
||||
if (this.pointOnLineSegment(x, y, xi, yi, xj, yj))
|
||||
return true;
|
||||
if (yi < y && yj >= y || yj < y && yi >= y) {
|
||||
if (yi <= y && yj > y || yj <= y && yi > y) {
|
||||
const slope = (xj - xi) / (yj - yi);
|
||||
const intersectX = xi + (y - yi) * slope;
|
||||
if (x < intersectX) {
|
||||
if (x <= xi + (y - yi) * slope) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
@ -143,7 +127,7 @@ const _sfc_main = {
|
||||
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);
|
||||
const distance = Math.sqrt((x - projX) * 2 + (y - projY) * 2);
|
||||
return distance < 5;
|
||||
}
|
||||
return false;
|
||||
@ -165,12 +149,11 @@ const _sfc_main = {
|
||||
updateCanvasSize() {
|
||||
this.canvasDisplayWidth = this.width;
|
||||
this.canvasDisplayHeight = this.height;
|
||||
this.canvasActualWidth = this.width * this.dpr;
|
||||
this.canvasActualHeight = this.height * this.dpr;
|
||||
this.canvasActualWidth = this.width;
|
||||
this.canvasActualHeight = this.height;
|
||||
if (this.canvas) {
|
||||
this.canvas.width = this.canvasActualWidth;
|
||||
this.canvas.height = this.canvasActualHeight;
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
this.redraw();
|
||||
}
|
||||
},
|
||||
@ -190,26 +173,27 @@ const _sfc_main = {
|
||||
});
|
||||
this.redraw();
|
||||
} catch (e) {
|
||||
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:247", "图片加载失败:", e);
|
||||
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:223", "图片加载失败:", e);
|
||||
this.image = null;
|
||||
}
|
||||
},
|
||||
// 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方法中添加视图判断
|
||||
checkSeatHit(x, y) {
|
||||
if (!this.seatData)
|
||||
return null;
|
||||
const inverted = this.matrix.invertPoint(x, y, this.dpr);
|
||||
for (const seat of this.seatData) {
|
||||
const dx = seat.x - inverted.x;
|
||||
const dy = seat.y - inverted.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
if (distance < 8) {
|
||||
return seat;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
redraw() {
|
||||
var _a, _b, _c;
|
||||
if (!this.ctx)
|
||||
return;
|
||||
this.ctx.save();
|
||||
@ -218,7 +202,7 @@ const _sfc_main = {
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
const { a, b, c, d, tx, ty } = this.matrix;
|
||||
this.ctx.setTransform(a, b, c, d, tx, ty);
|
||||
if (this.image) {
|
||||
if (this.image && ((_a = this.$parent) == null ? void 0 : _a.currentView) === "area") {
|
||||
this.ctx.drawImage(
|
||||
this.image,
|
||||
0,
|
||||
@ -227,24 +211,47 @@ const _sfc_main = {
|
||||
this.canvasDisplayHeight
|
||||
);
|
||||
}
|
||||
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();
|
||||
});
|
||||
if (this.areaData && this.areaData.length > 0 && ((_b = this.$parent) == null ? void 0 : _b.currentView) === "area") {
|
||||
this.drawAreas();
|
||||
}
|
||||
if (this.seatData && this.seatData.length > 0 && ((_c = this.$parent) == null ? void 0 : _c.currentView) === "seat") {
|
||||
this.drawSeats();
|
||||
}
|
||||
this.ctx.restore();
|
||||
},
|
||||
// 添加绘制区域方法
|
||||
drawAreas() {
|
||||
this.areaData.forEach((area) => {
|
||||
const points = [];
|
||||
for (let i = 0; i < area.polygon.length; i += 2) {
|
||||
points.push([area.polygon[i], area.polygon[i + 1]]);
|
||||
}
|
||||
this.ctx.beginPath();
|
||||
points.forEach(([x, y], index) => {
|
||||
if (index === 0)
|
||||
this.ctx.moveTo(x, y);
|
||||
else
|
||||
this.ctx.lineTo(x, y);
|
||||
});
|
||||
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();
|
||||
});
|
||||
},
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
class TransformMatrix {
|
||||
constructor() {
|
||||
this.reset();
|
||||
@ -50,14 +51,14 @@ class TransformMatrix {
|
||||
};
|
||||
}
|
||||
// 添加逆矩阵转换方法
|
||||
invertPoint(x, y) {
|
||||
invertPoint(x, y, dpr) {
|
||||
common_vendor.index.__f__("log", "at pages/index/transform-matrix.js:65", "invertPoint:", dpr);
|
||||
const det = this.a * this.d - this.b * this.c;
|
||||
if (Math.abs(det) < 1e-4) {
|
||||
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
|
||||
x: (this.d * (x / dpr - this.tx) - this.c * (y / dpr - this.ty)) / det,
|
||||
y: (this.a * (y / dpr - this.ty) - this.b * (x / dpr - this.tx)) / det
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user