267 lines
7.5 KiB
JavaScript
267 lines
7.5 KiB
JavaScript
"use strict";
|
|
const common_vendor = require("../../common/vendor.js");
|
|
const _sfc_main = {
|
|
props: {
|
|
width: Number,
|
|
// 画布实际宽度(像素)
|
|
height: Number,
|
|
// 画布实际高度(像素)
|
|
imgUrl: String,
|
|
// 图片URL
|
|
matrix: {
|
|
// 变换矩阵
|
|
type: Object,
|
|
default: () => ({
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
tx: 0,
|
|
ty: 0
|
|
})
|
|
},
|
|
areaData: {},
|
|
seatData: {}
|
|
},
|
|
data() {
|
|
return {
|
|
canvasContext: null,
|
|
image: null,
|
|
dpr: 1,
|
|
canvasDisplayWidth: 800,
|
|
// 默认显示尺寸
|
|
canvasDisplayHeight: 600,
|
|
canvasActualWidth: 800,
|
|
// 实际像素尺寸
|
|
canvasActualHeight: 600
|
|
};
|
|
},
|
|
watch: {
|
|
imgUrl: {
|
|
handler(newUrl) {
|
|
if (newUrl)
|
|
this.loadImage(newUrl);
|
|
},
|
|
immediate: true
|
|
},
|
|
width: {
|
|
handler() {
|
|
this.updateCanvasSize();
|
|
},
|
|
immediate: true
|
|
},
|
|
height: {
|
|
handler() {
|
|
this.updateCanvasSize();
|
|
},
|
|
immediate: true
|
|
},
|
|
matrix: {
|
|
deep: true,
|
|
immediate: true,
|
|
// 添加立即触发
|
|
handler() {
|
|
this.$nextTick(this.redraw);
|
|
}
|
|
},
|
|
areaData: {
|
|
deep: true,
|
|
handler() {
|
|
this.$nextTick(this.redraw);
|
|
}
|
|
},
|
|
seatData: {
|
|
deep: true,
|
|
handler() {
|
|
this.$nextTick(this.redraw);
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.initCanvas();
|
|
},
|
|
methods: {
|
|
// 添加点击检测方法
|
|
checkHitArea(x, y) {
|
|
if (!this.areaData)
|
|
return null;
|
|
const inverted = this.matrix.invertPoint(x, y, this.dpr);
|
|
common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:92", "checkHitArea", inverted);
|
|
for (const area of this.areaData) {
|
|
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
|
|
return area;
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
pointInPolygon(x, y, polygon) {
|
|
const points = [];
|
|
for (let i = 0; i < polygon.length; i += 2) {
|
|
points.push([polygon[i], polygon[i + 1]]);
|
|
}
|
|
let inside = false;
|
|
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) {
|
|
const slope = (xj - xi) / (yj - yi);
|
|
if (x <= xi + (y - yi) * slope) {
|
|
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() {
|
|
const query = common_vendor.index.createSelectorQuery().in(this);
|
|
query.select("#myCanvas").fields({ node: true, size: true }).exec(async (res) => {
|
|
if (!res[0])
|
|
return;
|
|
this.canvas = res[0].node;
|
|
this.ctx = res[0].node.getContext("2d");
|
|
this.dpr = common_vendor.index.getSystemInfoSync().pixelRatio;
|
|
this.updateCanvasSize();
|
|
if (this.imgUrl) {
|
|
await this.loadImage(this.imgUrl);
|
|
}
|
|
});
|
|
},
|
|
updateCanvasSize() {
|
|
this.canvasDisplayWidth = this.width;
|
|
this.canvasDisplayHeight = this.height;
|
|
this.canvasActualWidth = this.width;
|
|
this.canvasActualHeight = this.height;
|
|
if (this.canvas) {
|
|
this.canvas.width = this.canvasActualWidth;
|
|
this.canvas.height = this.canvasActualHeight;
|
|
this.redraw();
|
|
}
|
|
},
|
|
async loadImage(src) {
|
|
try {
|
|
if (!this.canvas) {
|
|
await this.initCanvas();
|
|
}
|
|
this.image = await new Promise((resolve, reject) => {
|
|
if (!this.canvas) {
|
|
return;
|
|
}
|
|
const image = this.canvas.createImage();
|
|
image.src = src;
|
|
image.onload = () => resolve(image);
|
|
image.onerror = reject;
|
|
});
|
|
this.redraw();
|
|
} catch (e) {
|
|
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:223", "图片加载失败:", e);
|
|
this.image = null;
|
|
}
|
|
},
|
|
// 在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();
|
|
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);
|
|
if (this.image && ((_a = this.$parent) == null ? void 0 : _a.currentView) === "area") {
|
|
this.ctx.drawImage(
|
|
this.image,
|
|
0,
|
|
0,
|
|
this.canvasDisplayWidth,
|
|
this.canvasDisplayHeight
|
|
);
|
|
}
|
|
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();
|
|
});
|
|
}
|
|
}
|
|
};
|
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
return {
|
|
a: `${$data.canvasDisplayWidth}px`,
|
|
b: `${$data.canvasDisplayHeight}px`
|
|
};
|
|
}
|
|
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
wx.createComponent(Component);
|
|
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/transform-canvas.js.map
|